From 2ef37a302f2b1f3e9e8cef2c8c08795dbbce896c Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 19:29:59 +0800 Subject: [PATCH 01/38] chore(abi): freeze pre-submitters cutover baselines --- contracts/abi/archive/README.md | 12 + .../archive/legacy-l1-staking/L1Staking.json | 1033 ++++++++++++ contracts/abi/archive/manifest.json | 13 + .../abi/archive/pre-submitter/Rollup.json | 1416 +++++++++++++++++ .../archive/Rollup.pre-submitter.json | 424 +++++ .../app/src/abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ node/types/abi/pre_submitter_rollup.json | 1416 +++++++++++++++++ .../src/abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ .../abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ 9 files changed, 8562 insertions(+) create mode 100644 contracts/abi/archive/README.md create mode 100644 contracts/abi/archive/legacy-l1-staking/L1Staking.json create mode 100644 contracts/abi/archive/manifest.json create mode 100644 contracts/abi/archive/pre-submitter/Rollup.json create mode 100644 contracts/storage-layout/archive/Rollup.pre-submitter.json create mode 100644 gas-oracle/app/src/abi/pre_submitter/Rollup.json create mode 100644 node/types/abi/pre_submitter_rollup.json create mode 100644 prover/bin/challenge/src/abi/pre_submitter/Rollup.json create mode 100644 prover/bin/shadow-prove/abi/pre_submitter/Rollup.json diff --git a/contracts/abi/archive/README.md b/contracts/abi/archive/README.md new file mode 100644 index 000000000..20b3253a3 --- /dev/null +++ b/contracts/abi/archive/README.md @@ -0,0 +1,12 @@ +# Archived production ABIs + +These ABI-only artifacts are immutable compatibility inputs for the centralized +submitter cutover. They were frozen from the pre-Submitter source tree before +the current Rollup ABI was regenerated. + +- `pre-submitter/Rollup.json` decodes the three production submission methods + that still include `BatchSignatureInput`. +- `legacy-l1-staking/L1Staking.json` is the only runtime interface used by the + L1 staking retirement tooling after the legacy Solidity source is removed. + +Do not regenerate or overwrite these files from the current contracts. diff --git a/contracts/abi/archive/legacy-l1-staking/L1Staking.json b/contracts/abi/archive/legacy-l1-staking/L1Staking.json new file mode 100644 index 000000000..e8d86b6d8 --- /dev/null +++ b/contracts/abi/archive/legacy-l1-staking/L1Staking.json @@ -0,0 +1,1033 @@ +[ + { + "inputs": [ + { + "internalType": "address payable", + "name": "_messenger", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldChallengeDeposit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newChallengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeDepositUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGasLimit", + "type": "uint256" + } + ], + "name": "GasLimitAddStakerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGasLimit", + "type": "uint256" + } + ], + "name": "GasLimitRemoveStakersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "name": "Registered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercentage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercentage", + "type": "uint256" + } + ], + "name": "RewardPercentageUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SlashRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "Slashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "StakersRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldStakingValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newStakingValue", + "type": "uint256" + } + ], + "name": "StakingValueUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "add", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "remove", + "type": "address[]" + } + ], + "name": "WhitelistUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unlockHeight", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [], + "name": "MESSENGER", + "outputs": [ + { + "internalType": "contract ICrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OTHER_STAKING", + "outputs": [ + { + "internalType": "contract Staking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "blsPubkey", + "type": "bytes" + } + ], + "name": "blsKeys", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "challengeDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimSlashRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cleanStakerStore", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "deleteList", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "deleteableHeight", + "outputs": [ + { + "internalType": "uint256", + "name": "height", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasLimitAddStaker", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasLimitRemoveStakers", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getActiveStakers", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_staker", + "type": "address" + } + ], + "name": "getStakerBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakers", + "outputs": [ + { + "internalType": "address[255]", + "name": "", + "type": "address[255]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_stakers", + "type": "address[]" + } + ], + "name": "getStakersBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "name": "getStakersFromBitmap", + "outputs": [ + { + "internalType": "address[]", + "name": "stakerAddrs", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rollupContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_stakingValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_lockBlocks", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_rewardPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimitAdd", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimitRemove", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isActiveStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isStakerInDeleteList", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messenger", + "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": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "name": "register", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_stakers", + "type": "address[]" + } + ], + "name": "removeStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "removedList", + "outputs": [ + { + "internalType": "bool", + "name": "removed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sequencersBitmap", + "type": "uint256" + } + ], + "name": "slash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "stakerIndexes", + "outputs": [ + { + "internalType": "uint8", + "name": "index", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "stakerSet", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "stakers", + "outputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakingValue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "tmPubkey", + "type": "bytes32" + } + ], + "name": "tmKeys", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_challengeDeposit", + "type": "uint256" + } + ], + "name": "updateChallengeDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasLimitAdd", + "type": "uint256" + } + ], + "name": "updateGasLimitAddStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasLimitRemove", + "type": "uint256" + } + ], + "name": "updateGasLimitRemoveStakers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rewardPercentage", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_stakingValue", + "type": "uint256" + } + ], + "name": "updateStakingValue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "add", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "remove", + "type": "address[]" + } + ], + "name": "updateWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "", + "type": "address[]" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "verifySignature", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "whitelist", + "outputs": [ + { + "internalType": "bool", + "name": "inWhitelist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawalLockBlocks", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "withdrawals", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/contracts/abi/archive/manifest.json b/contracts/abi/archive/manifest.json new file mode 100644 index 000000000..fd4d36083 --- /dev/null +++ b/contracts/abi/archive/manifest.json @@ -0,0 +1,13 @@ +{ + "sourceCommit": "3d21e1f45f743b7fb4131fd6655ceb4d99f15356", + "artifacts": { + "pre-submitter/Rollup.json": "aea8c9f75f2c8e132a4ffca3f0bb3f6abd83ae2ae9457827a099e75463c5c03a", + "legacy-l1-staking/L1Staking.json": "df14c1e4264ba93661b1476ed9166ab06e03d077713fa13b16fded7f1dd6eb46", + "../../storage-layout/archive/Rollup.pre-submitter.json": "f8a745e49d6ea6e141ae26440ce12d6b2feeb155ef1dfdbe9dff40d124c59c37" + }, + "selectors": { + "commitBatch": "0x428868b5", + "commitState": "0x1e8825be", + "commitBatchWithProof": "0x4e8f1d67" + } +} diff --git a/contracts/abi/archive/pre-submitter/Rollup.json b/contracts/abi/archive/pre-submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/contracts/abi/archive/pre-submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/contracts/storage-layout/archive/Rollup.pre-submitter.json b/contracts/storage-layout/archive/Rollup.pre-submitter.json new file mode 100644 index 000000000..847c1cf90 --- /dev/null +++ b/contracts/storage-layout/archive/Rollup.pre-submitter.json @@ -0,0 +1,424 @@ +{ + "storage": [ + { + "astId": 123005, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 123008, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 125558, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 122758, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 122878, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 123189, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_paused", + "offset": 0, + "slot": "101", + "type": "t_bool" + }, + { + "astId": 123294, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 8103, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "l1StakingContract", + "offset": 0, + "slot": "151", + "type": "t_address" + }, + { + "astId": 8106, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizationPeriodSeconds", + "offset": 0, + "slot": "152", + "type": "t_uint256" + }, + { + "astId": 8109, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proofWindow", + "offset": 0, + "slot": "153", + "type": "t_uint256" + }, + { + "astId": 8112, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__maxNumTxInChunk", + "offset": 0, + "slot": "154", + "type": "t_uint256" + }, + { + "astId": 8115, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "messageQueue", + "offset": 0, + "slot": "155", + "type": "t_address" + }, + { + "astId": 8118, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "verifier", + "offset": 0, + "slot": "156", + "type": "t_address" + }, + { + "astId": 8122, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "lastFinalizedBatchIndex", + "offset": 0, + "slot": "157", + "type": "t_uint256" + }, + { + "astId": 8126, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "lastCommittedBatchIndex", + "offset": 0, + "slot": "158", + "type": "t_uint256" + }, + { + "astId": 8131, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "isChallenger", + "offset": 0, + "slot": "159", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 8137, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizedStateRoots", + "offset": 0, + "slot": "160", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8143, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "committedBatches", + "offset": 0, + "slot": "161", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8149, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchDataStore", + "offset": 0, + "slot": "162", + "type": "t_mapping(t_uint256,t_struct(BatchData)6917_storage)" + }, + { + "astId": 8154, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "withdrawalRoots", + "offset": 0, + "slot": "163", + "type": "t_mapping(t_bytes32,t_bool)" + }, + { + "astId": 8160, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challenges", + "offset": 0, + "slot": "164", + "type": "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)" + }, + { + "astId": 8165, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchChallengeReward", + "offset": 0, + "slot": "165", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 8168, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "inChallenge", + "offset": 0, + "slot": "166", + "type": "t_bool" + }, + { + "astId": 8171, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchChallenged", + "offset": 0, + "slot": "167", + "type": "t_uint256" + }, + { + "astId": 8174, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "revertReqIndex", + "offset": 0, + "slot": "168", + "type": "t_uint256" + }, + { + "astId": 8177, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proofRewardPercent", + "offset": 0, + "slot": "169", + "type": "t_uint256" + }, + { + "astId": 8180, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proveRemaining", + "offset": 0, + "slot": "170", + "type": "t_uint256" + }, + { + "astId": 8185, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "committedStateRoots", + "offset": 0, + "slot": "171", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8188, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "rollupDelayPeriod", + "offset": 0, + "slot": "172", + "type": "t_uint256" + }, + { + "astId": 8193, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchBlobVersionedHashes", + "offset": 0, + "slot": "173", + "type": "t_mapping(t_uint256,t_bytes32)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568", + "base": "t_uint256" + }, + "t_array(t_uint256)50_storage": { + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600", + "base": "t_uint256" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_bytes32,t_bool)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_bytes32)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct IRollup.BatchChallenge)", + "numberOfBytes": "32", + "value": "t_struct(BatchChallenge)6931_storage" + }, + "t_mapping(t_uint256,t_struct(BatchData)6917_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct IRollup.BatchData)", + "numberOfBytes": "32", + "value": "t_struct(BatchData)6917_storage" + }, + "t_struct(BatchChallenge)6931_storage": { + "encoding": "inplace", + "label": "struct IRollup.BatchChallenge", + "numberOfBytes": "128", + "members": [ + { + "astId": 6920, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchIndex", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 6922, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challenger", + "offset": 8, + "slot": "0", + "type": "t_address" + }, + { + "astId": 6924, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challengeDeposit", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 6926, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "startTime", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 6928, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challengeSuccess", + "offset": 0, + "slot": "3", + "type": "t_bool" + }, + { + "astId": 6930, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finished", + "offset": 1, + "slot": "3", + "type": "t_bool" + } + ] + }, + "t_struct(BatchData)6917_storage": { + "encoding": "inplace", + "label": "struct IRollup.BatchData", + "numberOfBytes": "128", + "members": [ + { + "astId": 6910, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "originTimestamp", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 6912, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizeTimestamp", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 6914, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "blockNumber", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 6916, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "signedSequencersBitmap", + "offset": 0, + "slot": "3", + "type": "t_uint256" + } + ] + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } +} diff --git a/gas-oracle/app/src/abi/pre_submitter/Rollup.json b/gas-oracle/app/src/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/gas-oracle/app/src/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/node/types/abi/pre_submitter_rollup.json b/node/types/abi/pre_submitter_rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/node/types/abi/pre_submitter_rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] From d708a45829e268b2b7743d0fbe9a1974efebbb05 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:31:30 +0800 Subject: [PATCH 02/38] feat(contracts): replace staking authority with submitters --- contracts/abi/archive/README.md | 5 +- .../archive/legacy-l1-staking/IL1Staking.json | 1 + contracts/abi/archive/manifest.json | 1 + contracts/contracts/Staking.md | 134 -- contracts/contracts/l1/rollup/BLS.sol | 4 - contracts/contracts/l1/rollup/IRollup.sol | 39 +- contracts/contracts/l1/rollup/ISubmitter.sol | 18 + contracts/contracts/l1/rollup/Rollup.sol | 193 ++- contracts/contracts/l1/rollup/Submitter.sol | 221 ++++ contracts/contracts/l1/staking/IL1Staking.sol | 119 -- contracts/contracts/l1/staking/L1Staking.sol | 515 -------- contracts/contracts/test/L1Staking.t.sol | 1154 ----------------- contracts/contracts/test/Rollup.t.sol | 591 ++++++--- contracts/contracts/test/Submitter.t.sol | 461 +++++++ .../contracts/test/base/L1MessageBase.t.sol | 41 +- 15 files changed, 1216 insertions(+), 2281 deletions(-) create mode 100644 contracts/abi/archive/legacy-l1-staking/IL1Staking.json delete mode 100644 contracts/contracts/Staking.md delete mode 100644 contracts/contracts/l1/rollup/BLS.sol create mode 100644 contracts/contracts/l1/rollup/ISubmitter.sol create mode 100644 contracts/contracts/l1/rollup/Submitter.sol delete mode 100644 contracts/contracts/l1/staking/IL1Staking.sol delete mode 100644 contracts/contracts/l1/staking/L1Staking.sol delete mode 100644 contracts/contracts/test/L1Staking.t.sol create mode 100644 contracts/contracts/test/Submitter.t.sol diff --git a/contracts/abi/archive/README.md b/contracts/abi/archive/README.md index 20b3253a3..15697249e 100644 --- a/contracts/abi/archive/README.md +++ b/contracts/abi/archive/README.md @@ -6,7 +6,8 @@ the current Rollup ABI was regenerated. - `pre-submitter/Rollup.json` decodes the three production submission methods that still include `BatchSignatureInput`. -- `legacy-l1-staking/L1Staking.json` is the only runtime interface used by the - L1 staking retirement tooling after the legacy Solidity source is removed. +- `legacy-l1-staking/IL1Staking.json` preserves the retired public protocol + interface, while `legacy-l1-staking/L1Staking.json` is the complete runtime + interface used by the retirement tooling after the Solidity source is removed. Do not regenerate or overwrite these files from the current contracts. diff --git a/contracts/abi/archive/legacy-l1-staking/IL1Staking.json b/contracts/abi/archive/legacy-l1-staking/IL1Staking.json new file mode 100644 index 000000000..21a217018 --- /dev/null +++ b/contracts/abi/archive/legacy-l1-staking/IL1Staking.json @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChallengeDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChallengeDeposit","type":"uint256"}],"name":"ChallengeDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"GasLimitAddStakerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"GasLimitRemoveStakersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bytes32","name":"tmKey","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"blsKey","type":"bytes"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPercentage","type":"uint256"}],"name":"RewardPercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SlashRemainingClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"Slashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"StakersRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStakingValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStakingValue","type":"uint256"}],"name":"StakingValueUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"add","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"remove","type":"address[]"}],"name":"WhitelistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"unlockHeight","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"challengeDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getActiveStakers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakerBitmap","outputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakers","outputs":[{"internalType":"address[255]","name":"","type":"address[255]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"getStakersBitmap","outputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isActiveStaker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isStaker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sequencersBitmap","type":"uint256"}],"name":"slash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"signedSequencersBitmap","type":"uint256"},{"internalType":"address[]","name":"sequencerSet","type":"address[]"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verifySignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/contracts/abi/archive/manifest.json b/contracts/abi/archive/manifest.json index fd4d36083..1afdd8748 100644 --- a/contracts/abi/archive/manifest.json +++ b/contracts/abi/archive/manifest.json @@ -2,6 +2,7 @@ "sourceCommit": "3d21e1f45f743b7fb4131fd6655ceb4d99f15356", "artifacts": { "pre-submitter/Rollup.json": "aea8c9f75f2c8e132a4ffca3f0bb3f6abd83ae2ae9457827a099e75463c5c03a", + "legacy-l1-staking/IL1Staking.json": "cadf899ad272d9018a3009cd8d5ad4a70760d9a6cddf52de44498f5024ef0ad3", "legacy-l1-staking/L1Staking.json": "df14c1e4264ba93661b1476ed9166ab06e03d077713fa13b16fded7f1dd6eb46", "../../storage-layout/archive/Rollup.pre-submitter.json": "f8a745e49d6ea6e141ae26440ce12d6b2feeb155ef1dfdbe9dff40d124c59c37" }, diff --git a/contracts/contracts/Staking.md b/contracts/contracts/Staking.md deleted file mode 100644 index b657c8114..000000000 --- a/contracts/contracts/Staking.md +++ /dev/null @@ -1,134 +0,0 @@ -# Staking - ---- - -## Core Process - -**Staking & Sequencer Selection** - -Morph token staking will be divided into three stages: - -- MorphToken has not yet issued yet -- MorphToken has been issued, but inflation and staking rewards have not started yet. -- Inflation starts and distribute staking rewards - -1. `L1` Update whitelist -2. `L1` Register and stake eth to become staker -3. `L1->L2` Send {add staker} message -4. `L2` Update stakers -5. `L2` Delegate stake MorphToken to staker -6. `L2` Update sequencer set by amount of MorphToken delegation - -**Rollp Verify** - -- The submitted batch requires the BLS signature of more than 2/3 of the sequencers -- Before BLS implementation, only staker (not withdrawing, not slashing) can rollup - -1. `L1` Submit batch and sequencer sets -2. `L1` Verify sequencer set -3. `L1` Verify batch signature - -**Slash Sequencers After Challenger Win** - -- Sequencer will be confiscated all stake amount and removed from sequencer set if defense challenge fails -- Even if challenged repeatedly, each sequencer will only be slashed once -- The reward for a successful challenge is a fixed proportion of the staking amount, and is greater than the challenge deposit -- If the slash causes the number of sequences to be 0, then the layer2 will stop running. We can restart by upgrading, reset stakers and sequencer set. This does not affect the security of the evm state - -1. `L1` Slash staking value of signed sequencers and remove from stakers -2. `L1` Distribute challenger rewards -3. `L1->L2` Send {remove stakers} message -4. `L2` Update sequencer set by amount of MorphToken delegation - -**Delegation Rewards** - -- MorphToken is inflated at a fixed ratio every day, and the additional tokens are used as rewards for sequencers and delegators -- The sequencer and his delegators get MorphToken inflation reward according to the block production ratio -- Sequencer charges commission as its own income -- Users get remaining reward according to their delegation amount - -1. `L2` Staker set delegation commission rate -2. `L2` Upload sequencers work records in epoch (an epoch is a day) -3. `L2` Mint MorphToken inflation as delegation reward -4. `L2` Claim delegation reward or claim commission - -**Quit Staker** - -The exit lock period should be long enough to ensure that stakers and sequencers in L2 have been updated - -1. `L1` Apply to withdraw, remove from staker list, enter lock period -2. `L1->L2` Send {remove staker} message -3. `L2` Remove from stakers and sequencers if needed -4. `L1` Claim allowed until reach unlock height,remove staker info after claiming - ---- - -## Contracts - -### L1 Contract - -#### L1Staking Contract - -**Main functions** - -- Update whitelist -- Register as staker -- Staker quit -- Slash signed sequencers if challenger win, call by rollup contract - -#### Rollup Contract - -**Main functions** - -- Commit batch & verify -- Challenge batch - -### L2 Contract - -#### MorphToken Contract - -**Main functions** - -- Mint inflation - -#### Record Contract - -**Main functions** - -- Record finalized batch submissions, call by oracle -- Record rollup epochs, call by oracle -- Record reward epochs, call by oracle - -#### L2Staking Contract - -**Main functions** - -- Add staker, sync from L1 staking contract -- Remove stakers, sync from L1 staking contract -- Staker set commission rate -- User delegate stake morph token -- User undelegate stake morph token -- User claim delegation reward -- Sequencer claim commission - -#### Sequencer Contract - -**Main functions** - -- Update sequencer set, call form l2 staking contract - -#### Distribute Contract - -**Main functions** - -- Record delegation info by l2 staking contract -- Record undelegation info by l2 staking contract -- Compute delegator's delegation reward, call form l2 staking contract -- Compute sequencer's commission, call form l2 staking contract - -#### Gov Contract - -**Main functions** - -- Submit proposal -- Vote proposal diff --git a/contracts/contracts/l1/rollup/BLS.sol b/contracts/contracts/l1/rollup/BLS.sol deleted file mode 100644 index 5f78c7036..000000000 --- a/contracts/contracts/l1/rollup/BLS.sol +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -contract BLS {} diff --git a/contracts/contracts/l1/rollup/IRollup.sol b/contracts/contracts/l1/rollup/IRollup.sol index d6691cb14..1394916d9 100644 --- a/contracts/contracts/l1/rollup/IRollup.sol +++ b/contracts/contracts/l1/rollup/IRollup.sol @@ -23,23 +23,15 @@ interface IRollup { bytes32 withdrawalRoot; } - /// @param signedSequencers The bitmap of signed sequencers - /// @param sequencerSets The latest 3 sequencer sets - /// @param signature The BLS signature - struct BatchSignatureInput { - uint256 signedSequencersBitmap; - bytes sequencerSets; - bytes signature; - } - /// @param originTimestamp /// @param finalizeTimestamp /// @param blockNumber + /// @param submitter The account responsible for the batch, or zero for permissionless submissions. struct BatchData { uint256 originTimestamp; uint256 finalizeTimestamp; uint256 blockNumber; - uint256 signedSequencersBitmap; + address submitter; } /// @dev Structure to store information about a batch challenge. @@ -128,6 +120,9 @@ interface IRollup { /// @param amount claimed amount. event ProveRemainingClaimed(address receiver, uint256 amount); + /// @notice Emitted when the legacy staking dependency is replaced with Submitter. + event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr); + /// @notice Emitted when the state of Challenge is updated. /// @param batchIndex The index of the batch. /// @param challenger The address of challenger. @@ -174,36 +169,30 @@ interface IRollup { /// @notice Return the rollup config of finalizationPeriodSeconds. function finalizationPeriodSeconds() external view returns (uint256); + /// @notice Number of committed, non-terminated batches attributable to a submitter. + function pendingBatchCount(address submitter) external view returns (uint256); + /***************************** * Public Mutating Functions * *****************************/ /// @notice Commit a batch of transactions on layer 1. /// - /// @param batchDataInput The BatchDataInput struct - /// @param batchSignatureInput The BatchSignatureInput struct - function commitBatch( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external payable; + /// @param batchDataInput The BatchDataInput struct + function commitBatch(BatchDataInput calldata batchDataInput) external payable; /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). /// @dev Requires batchBlobVersionedHashes[nextBatchIndex] != 0. - function commitState( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external; + function commitState(BatchDataInput calldata batchDataInput) external; /// @notice Commit a batch with ZKP proof for permissionless submission. /// @dev This function allows anyone to submit batches when the sequencer is offline or censoring. /// - /// @param batchDataInput The BatchDataInput struct - /// @param batchSignatureInput The BatchSignatureInput struct - /// @param batchHeader The batch header for ZKP verification - /// @param batchProof The ZKP proof data + /// @param batchDataInput The BatchDataInput struct + /// @param batchHeader The batch header for ZKP verification + /// @param batchProof The ZKP proof data function commitBatchWithProof( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, bytes calldata batchHeader, bytes calldata batchProof ) external; diff --git a/contracts/contracts/l1/rollup/ISubmitter.sol b/contracts/contracts/l1/rollup/ISubmitter.sol new file mode 100644 index 000000000..57747a235 --- /dev/null +++ b/contracts/contracts/l1/rollup/ISubmitter.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +/// @notice Runtime interface used by Rollup after the centralized submitter cutover. +interface ISubmitter { + function rollupContract() external view returns (address); + + function isActive(address submitter) external view returns (bool); + + function challengeDeposit() external view returns (uint256); + + function slash(address submitter) external returns (uint256 reward); +} + +/// @notice Bounded liability view used by Submitter before releasing stake. +interface IRollupSubmitterView { + function pendingBatchCount(address submitter) external view returns (uint256); +} diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 14aae181b..77d80454a 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -9,7 +9,7 @@ import {BatchHeaderCodecV1} from "../../libraries/codec/BatchHeaderCodecV1.sol"; import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol"; import {IL1MessageQueue} from "./IL1MessageQueue.sol"; import {IRollup} from "./IRollup.sol"; -import {IL1Staking} from "../staking/IL1Staking.sol"; +import {ISubmitter} from "./ISubmitter.sol"; // solhint-disable no-inline-assembly // solhint-disable reason-string @@ -24,13 +24,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice The zero versioned hash. bytes32 internal constant ZERO_VERSIONED_HASH = 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014; - /// @notice The BLS MODULUS. Deprecated. - uint256 internal constant __BLS_MODULUS = - 52435875175126190479447740508185965837690552500527637822603658699938581184513; - - /// @dev Address of the point evaluation precompile used for EIP-4844 blob verification. - address internal constant POINT_EVALUATION_PRECOMPILE_ADDR = address(0x0A); - /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable LAYER_2_CHAIN_ID; @@ -38,8 +31,9 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { * Variables * *************/ - /// @notice L1 staking contract - address public l1StakingContract; + /// @notice Submitter registration and staking contract. + /// @dev Occupies the legacy staking dependency's storage slot. + address public submitterContract; /// @notice Batch challenge time. uint256 public finalizationPeriodSeconds; @@ -109,13 +103,16 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Placed after rollupDelayPeriod for upgrade-safe storage layout (forward compatibility). mapping(uint256 batchIndex => bytes32 blobVersionedHash) public batchBlobVersionedHashes; + /// @inheritdoc IRollup + mapping(address submitter => uint256 count) public override pendingBatchCount; + /********************** * Function Modifiers * **********************/ - /// @notice Only active staker allowed. - modifier onlyActiveStaker() { - require(IL1Staking(l1StakingContract).isActiveStaker(_msgSender()), "only active staker allowed"); + /// @notice Only an active submitter is allowed. + modifier onlyActiveSubmitter() { + require(ISubmitter(submitterContract).isActive(_msgSender()), "only active submitter allowed"); _; } @@ -150,13 +147,13 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ***************/ /// @notice initializer - /// @param _l1StakingContract l1 staking contract + /// @param _submitterContract submitter contract /// @param _messageQueue message queue /// @param _verifier verifier /// @param _finalizationPeriodSeconds finalization period seconds /// @param _proofWindow proof window function initialize( - address _l1StakingContract, + address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, @@ -166,12 +163,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (_messageQueue == address(0) || _verifier == address(0)) { revert ErrZeroAddress(); } - require(_l1StakingContract != address(0), "invalid l1 staking contract"); + require(_submitterContract != address(0), "invalid submitter contract"); __Pausable_init(); __Ownable_init(); - l1StakingContract = _l1StakingContract; + submitterContract = _submitterContract; messageQueue = _messageQueue; verifier = _verifier; finalizationPeriodSeconds = _finalizationPeriodSeconds; @@ -183,7 +180,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { emit UpdateProofRewardPercent(0, _proofRewardPercent); } - function initialize2(bytes32 _prevStateRoot) external reinitializer(2) { + function initialize2(bytes32 _prevStateRoot) external reinitializer(2) onlyOwner { require(_getInitializedVersion() == 2, "must have initialized!"); require(_prevStateRoot != bytes32(0), "can not set state root with bytes32(0)!"); @@ -194,12 +191,42 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice Initializer for upgrade to version 3. /// @param _rollupDelayPeriod The delay period for permissionless batch submission. - function initialize3(uint256 _rollupDelayPeriod) external reinitializer(3) { + function initialize3(uint256 _rollupDelayPeriod) external reinitializer(3) onlyOwner { require(_rollupDelayPeriod != 0, "invalid rollup delay period"); rollupDelayPeriod = _rollupDelayPeriod; emit UpdateRollupDelayPeriod(0, _rollupDelayPeriod); } + /// @notice One-time cutover from the legacy staking address to the Submitter proxy. + /// @dev The cutover is deliberately gated by an empty pending-batch tail, not by pause state. + function initialize4(address _newSubmitter) external reinitializer(4) onlyOwner { + require(_newSubmitter != address(0) && _newSubmitter.code.length > 0, "invalid submitter"); + + bytes32 _declaredRollupRaw = _staticcallExact32( + _newSubmitter, + abi.encodeCall(ISubmitter.rollupContract, ()) + ); + require(uint256(_declaredRollupRaw) >> 160 == 0, "invalid rollup encoding"); + address _declaredRollup = address(uint160(uint256(_declaredRollupRaw))); + uint256 _zeroAddressActive = uint256( + _staticcallExact32(_newSubmitter, abi.encodeCall(ISubmitter.isActive, (address(0)))) + ); + uint256 _challengeDeposit = uint256( + _staticcallExact32(_newSubmitter, abi.encodeCall(ISubmitter.challengeDeposit, ())) + ); + + require(_declaredRollup == address(this), "submitter rollup mismatch"); + require(_zeroAddressActive == 0 && _challengeDeposit > 0, "invalid submitter state"); + require(lastCommittedBatchIndex == lastFinalizedBatchIndex, "pending batches"); + require(revertReqIndex == 0, "pending revert request"); + + // The last finalized entry survives normal GC. Clear only the legacy bitmap slot so it + // cannot be interpreted as a submitter address after the storage-compatible type change. + batchDataStore[lastFinalizedBatchIndex].submitter = address(0); + emit SubmitterContractUpdated(submitterContract, _newSubmitter); + submitterContract = _newSubmitter; + } + /************************ * Restricted Functions * ************************/ @@ -221,7 +248,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { require(BatchHeaderCodecV0.getBlobVersionedHash(memPtr) == ZERO_VERSIONED_HASH, "invalid versioned hash"); committedBatches[_batchIndex] = _batchHash; - batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, 0); + batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, address(0)); batchBlobVersionedHashes[_batchIndex] = BatchHeaderCodecV0.getBlobVersionedHash(memPtr); committedStateRoots[_batchIndex] = _postStateRoot; @@ -235,29 +262,23 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @inheritdoc IRollup function commitBatch( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external payable override onlyActiveStaker nonReqRevert whenNotPaused { - // check if the next batch has a stored blob hash - (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); - uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; - require(batchBlobVersionedHashes[_nextBatchIndex] == bytes32(0), "commitBatch requires no stored blob hash"); + BatchDataInput calldata batchDataInput + ) external payable override onlyActiveSubmitter nonReqRevert whenNotPaused { + require(blobhash(0) != bytes32(0), "must carry blob"); if ( IL1MessageQueue(messageQueue).getFirstUnfinalizedMessageEnqueueTime() + rollupDelayPeriod < block.timestamp ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); bytes32 _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); - _commitBatchWithBatchData(batchDataInput, batchSignatureInput, submitterBitmap, _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, _msgSender(), _blobVersionedHash); } /// @inheritdoc IRollup /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). function commitState( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external override onlyActiveStaker nonReqRevert whenNotPaused { + BatchDataInput calldata batchDataInput + ) external override onlyActiveSubmitter nonReqRevert whenNotPaused { require(blobhash(0) == bytes32(0), "commitState must not carry blob"); (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; @@ -267,19 +288,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); - _commitBatchWithBatchData( - batchDataInput, - batchSignatureInput, - submitterBitmap, - batchBlobVersionedHashes[_nextBatchIndex] - ); + _commitBatchWithBatchData(batchDataInput, _msgSender(), batchBlobVersionedHashes[_nextBatchIndex]); } function _commitBatchWithBatchData( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, - uint256 submitterBitmap, + address submitter, bytes32 blobVersionedHash ) internal { require(batchDataInput.version <= 2, "invalid version"); @@ -340,10 +354,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { BatchHeaderCodecV0.storePrevStateHash(_batchPtr, batchDataInput.prevStateRoot); BatchHeaderCodecV0.storePostStateHash(_batchPtr, batchDataInput.postStateRoot); BatchHeaderCodecV0.storeWithdrawRootHash(_batchPtr, batchDataInput.withdrawalRoot); - BatchHeaderCodecV0.storeSequencerSetVerifyHash( - _batchPtr, - keccak256(batchSignatureInput.sequencerSets) - ); + BatchHeaderCodecV0.storeSequencerSetVerifyHash(_batchPtr, bytes32(0)); BatchHeaderCodecV0.storeParentBatchHash(_batchPtr, _parentBatchHash); if (batchDataInput.version >= 1) { BatchHeaderCodecV1.storeLastBlockNumber(_batchPtr, batchDataInput.lastBlockNumber); @@ -362,24 +373,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { block.timestamp, block.timestamp + finalizationPeriodSeconds + proveRemainingTime, batchDataInput.lastBlockNumber, - // Before BLS is implemented, the accuracy of the sequencer set uploaded by rollup cannot be guaranteed. - // Therefore, if the batch is successfully challenged, only the submitter will be punished. - submitterBitmap // => batchSignature.signedSequencersBitmap + submitter ); + _increaseLiability(submitter); lastCommittedBatchIndex = _batchIndex; } - - // verify bls signature - require( - IL1Staking(l1StakingContract).verifySignature( - batchSignatureInput.signedSequencersBitmap, - _getValidSequencerSet(batchSignatureInput.sequencerSets, 0), - _getBLSMsgHash(batchDataInput), - batchSignatureInput.signature - ), - "the signature verification failed" - ); emit CommitBatch(_batchIndex, committedBatches[_batchIndex]); } @@ -388,7 +387,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// Entry conditions: rollup delay OR L1 message queue delay must be met. function commitBatchWithProof( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, bytes calldata _batchHeader, bytes calldata _batchProof ) external override nonReqRevert whenNotPaused { @@ -416,7 +414,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { } else { _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); } - _commitBatchWithBatchData(batchDataInput, batchSignatureInput, 0, _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, address(0), _blobVersionedHash); // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); @@ -452,6 +450,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { while (_count > 0) { emit RevertBatch(_batchIndex, _batchHash); + _releaseLiability(_batchIndex); committedBatches[_batchIndex] = bytes32(0); // if challenge exist and not finished yet, return challenge deposit to challenger if (batchInChallenge(_batchIndex)) { @@ -488,7 +487,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { // check challenge window require(batchInsideChallengeWindow(batchIndex), "cannot challenge batch outside the challenge window"); // check challenge amount - require(msg.value >= IL1Staking(l1StakingContract).challengeDeposit(), "insufficient value"); + require(msg.value >= ISubmitter(submitterContract).challengeDeposit(), "insufficient value"); batchChallenged = batchIndex; challenges[batchIndex] = BatchChallenge(batchIndex, _msgSender(), msg.value, block.timestamp, false, false); @@ -603,7 +602,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { function proveState( bytes calldata _batchHeader, bytes calldata _batchProof - ) external nonReqRevert whenNotPaused onlyActiveStaker { + ) external nonReqRevert whenNotPaused onlyActiveSubmitter { // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); // check batch hash @@ -621,7 +620,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (challenges[_batchIndex].startTime + proofWindow <= block.timestamp) { // set status challenges[_batchIndex].challengeSuccess = true; - _challengerWin(_batchIndex, batchDataStore[_batchIndex].signedSequencersBitmap, "Timeout"); + _challengerWin(_batchIndex, batchDataStore[_batchIndex].submitter, "Timeout"); } else { _verifyProof(memPtr, _batchProof); // Record defender win @@ -662,6 +661,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { BatchHeaderCodecV0.getL1MessagePopped(memPtr) ); + _releaseLiability(_batchIndex); delete batchDataStore[_batchIndex - 1]; delete committedStateRoots[_batchIndex - 1]; delete batchBlobVersionedHashes[_batchIndex - 1]; @@ -784,37 +784,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ); } - /// @dev Internal function to compute BLS msg hash - function _getBLSMsgHash( - BatchDataInput calldata // batchDataInput - ) internal pure returns (bytes32) { - // TODO compute bls message hash - return bytes32(0); - } - - /// @dev todo - function _getValidSequencerSet( - bytes calldata sequencerSets, - uint256 blockHeight - ) internal pure returns (address[] memory) { - // TODO require submitter was in valid sequencer set after BLS was implemented - ( - , - address[] memory sequencerSet0, - uint256 blockHeight1, - address[] memory sequencerSet1, - uint256 blockHeight2, - address[] memory sequencerSet2 - ) = abi.decode(sequencerSets, (uint256, address[], uint256, address[], uint256, address[])); - if (blockHeight >= blockHeight2) { - return sequencerSet2; - } - if (blockHeight >= blockHeight1) { - return sequencerSet1; - } - return sequencerSet0; - } - /// @dev Internal function executed when the defender wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. /// @param prover The zkProof prover address. @@ -829,16 +798,44 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Internal function executed when the challenger wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. - /// @param sequencersBitmap An array containing the sequencers to be slashed. + /// @param submitter The account responsible for the challenged batch. /// @param _type Description of the challenge type. - function _challengerWin(uint256 batchIndex, uint256 sequencersBitmap, string memory _type) internal { + function _challengerWin(uint256 batchIndex, address submitter, string memory _type) internal { revertReqIndex = batchIndex; address challenger = challenges[batchIndex].challenger; - uint256 reward = IL1Staking(l1StakingContract).slash(sequencersBitmap); + uint256 reward = ISubmitter(submitterContract).slash(submitter); batchChallengeReward[challenges[batchIndex].challenger] += (challenges[batchIndex].challengeDeposit + reward); emit ChallengeRes(batchIndex, challenger, _type); } + function _increaseLiability(address submitter) internal { + if (submitter != address(0)) { + pendingBatchCount[submitter] += 1; + } + } + + function _releaseLiability(uint256 batchIndex) internal { + address liable = batchDataStore[batchIndex].submitter; + if (liable == address(0)) return; + uint256 count = pendingBatchCount[liable]; + require(count > 0, "pending batch count underflow"); + pendingBatchCount[liable] = count - 1; + } + + function _staticcallExact32(address target, bytes memory input) internal view returns (bytes32 result) { + bool ok; + uint256 size; + assembly ("memory-safe") { + ok := staticcall(gas(), target, add(input, 0x20), mload(input), 0, 0) + size := returndatasize() + if and(ok, eq(size, 0x20)) { + returndatacopy(0, 0, 0x20) + result := mload(0) + } + } + require(ok && size == 32, "invalid submitter interface"); + } + /// @dev Internal function to transfer ETH to a specified address. /// @param _to The address to transfer ETH to. /// @param _amount The amount of ETH to transfer. diff --git a/contracts/contracts/l1/rollup/Submitter.sol b/contracts/contracts/l1/rollup/Submitter.sol new file mode 100644 index 000000000..0ed52cf4a --- /dev/null +++ b/contracts/contracts/l1/rollup/Submitter.sol @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; + +import {IRollupSubmitterView, ISubmitter} from "./ISubmitter.sol"; + +/// @title Submitter +/// @notice Registration, stake, exit, and slashing for centralized batch submitters. +contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable { + uint256 internal constant LIABILITY_QUERY_GAS_LIMIT = 50_000; + uint256 internal constant REFUND_GAS_LIMIT = 50_000; + + address public override rollupContract; + uint256 public minimumStake; + uint256 public override challengeDeposit; + uint256 public rewardPercentage; + uint256 public slashRemaining; + + mapping(address submitter => bool isRegistered) public registered; + mapping(address submitter => uint256 amount) public stakeOf; + mapping(address submitter => bool isExiting) public exiting; + mapping(address submitter => uint256 amount) public claimable; + + event SubmitterAdded(address indexed submitter); + event SubmitterRemoved(address indexed submitter); + event MinimumStakeUpdated(uint256 oldValue, uint256 newValue); + event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue); + event RewardPercentageUpdated(uint256 oldValue, uint256 newValue); + event Staked(address indexed submitter, uint256 amount, uint256 total); + event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount); + event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount); + event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit); + event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount); + event Slashed(address indexed submitter, uint256 amount, uint256 reward); + event SlashRemainingClaimed(address indexed receiver, uint256 amount); + + modifier onlyRollup() { + require(_msgSender() == rollupContract, "only rollup contract"); + _; + } + + constructor() { + _disableInitializers(); + } + + function initialize( + address owner_, + address rollupContract_, + uint256 minimumStake_, + uint256 challengeDeposit_, + uint256 rewardPercentage_ + ) external initializer { + require(owner_ != address(0), "invalid owner"); + require(rollupContract_ != address(0) && rollupContract_.code.length > 0, "invalid rollup contract"); + require(minimumStake_ > 0, "invalid minimum stake"); + require(challengeDeposit_ > 0, "invalid challenge deposit"); + require(rewardPercentage_ > 0 && rewardPercentage_ <= 100, "invalid reward percentage"); + + __Ownable_init(); + __ReentrancyGuard_init(); + _transferOwnership(owner_); + + rollupContract = rollupContract_; + minimumStake = minimumStake_; + challengeDeposit = challengeDeposit_; + rewardPercentage = rewardPercentage_; + + emit MinimumStakeUpdated(0, minimumStake_); + emit ChallengeDepositUpdated(0, challengeDeposit_); + emit RewardPercentageUpdated(0, rewardPercentage_); + } + + function isActive(address submitter) public view override returns (bool) { + return registered[submitter] && !exiting[submitter] && stakeOf[submitter] >= minimumStake; + } + + function addSubmitter(address submitter) external onlyOwner { + require(submitter != address(0) && !registered[submitter] && !exiting[submitter], "invalid submitter"); + registered[submitter] = true; + emit SubmitterAdded(submitter); + } + + function removeSubmitter(address submitter) external onlyOwner nonReentrant { + require(registered[submitter] && !exiting[submitter], "invalid submitter"); + registered[submitter] = false; + exiting[submitter] = true; + emit SubmitterRemoved(submitter); + emit WithdrawalRequested(submitter, submitter, stakeOf[submitter]); + _settleIfReleased(submitter, submitter); + } + + function setMinimumStake(uint256 value) external onlyOwner { + require(value > 0 && value != minimumStake, "invalid minimum stake"); + emit MinimumStakeUpdated(minimumStake, value); + minimumStake = value; + } + + function updateChallengeDeposit(uint256 value) external onlyOwner { + require(value > 0 && value != challengeDeposit, "invalid challenge deposit"); + emit ChallengeDepositUpdated(challengeDeposit, value); + challengeDeposit = value; + } + + function updateRewardPercentage(uint256 value) external onlyOwner { + require(value > 0 && value <= 100 && value != rewardPercentage, "invalid reward percentage"); + emit RewardPercentageUpdated(rewardPercentage, value); + rewardPercentage = value; + } + + function stake() external payable nonReentrant { + address submitter = _msgSender(); + require(registered[submitter] && !exiting[submitter], "not stakeable"); + uint256 total = stakeOf[submitter] + msg.value; + require(msg.value > 0 && total >= minimumStake, "below minimum stake"); + stakeOf[submitter] = total; + emit Staked(submitter, msg.value, total); + } + + function withdraw(address receiver) external nonReentrant { + address submitter = _msgSender(); + require(receiver != address(0), "invalid receiver"); + require(registered[submitter] && !exiting[submitter] && stakeOf[submitter] > 0, "not withdrawable"); + + // A completed exit always requires a fresh owner registration before staking again. + registered[submitter] = false; + exiting[submitter] = true; + emit WithdrawalRequested(submitter, receiver, stakeOf[submitter]); + _settleIfReleased(submitter, receiver); + } + + function claimWithdrawal(address receiver) external nonReentrant { + address submitter = _msgSender(); + require(receiver != address(0), "invalid receiver"); + require(exiting[submitter], "not exiting"); + require(_liabilityReleased(submitter), "pending batch liability"); + _settle(submitter, receiver); + } + + function claimCredit(address receiver) external nonReentrant { + address submitter = _msgSender(); + require(receiver != address(0), "invalid receiver"); + uint256 amount = claimable[submitter]; + require(amount > 0, "no credit"); + claimable[submitter] = 0; + _transfer(receiver, amount); + emit CreditClaimed(submitter, receiver, amount); + } + + function slash(address submitter) external override onlyRollup nonReentrant returns (uint256 reward) { + if (submitter == address(0)) return 0; + + uint256 amount = stakeOf[submitter]; + registered[submitter] = false; + stakeOf[submitter] = 0; + exiting[submitter] = true; + + reward = (amount * rewardPercentage) / 100; + slashRemaining += amount - reward; + _transfer(rollupContract, reward); + emit Slashed(submitter, amount, reward); + } + + function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { + require(receiver != address(0), "invalid receiver"); + uint256 amount = slashRemaining; + require(amount > 0, "no slash remaining"); + slashRemaining = 0; + _transfer(receiver, amount); + emit SlashRemainingClaimed(receiver, amount); + } + + function _settleIfReleased(address submitter, address receiver) internal { + if (_liabilityReleased(submitter)) _settle(submitter, receiver); + } + + function _settle(address submitter, address receiver) internal { + uint256 amount = stakeOf[submitter]; + stakeOf[submitter] = 0; + exiting[submitter] = false; + + if (amount == 0) { + emit WithdrawalPaid(submitter, receiver, 0); + return; + } + + (bool success,) = receiver.call{value: amount, gas: REFUND_GAS_LIMIT}(""); + if (success) { + emit WithdrawalPaid(submitter, receiver, amount); + } else { + claimable[submitter] += amount; + emit WithdrawalCredited(submitter, amount, claimable[submitter]); + } + } + + function _liabilityReleased(address submitter) internal view returns (bool) { + bytes memory input = abi.encodeCall(IRollupSubmitterView.pendingBatchCount, (submitter)); + address target = rollupContract; + bool ok; + uint256 size; + uint256 count; + assembly ("memory-safe") { + ok := staticcall(LIABILITY_QUERY_GAS_LIMIT, target, add(input, 0x20), mload(input), 0, 0) + size := returndatasize() + if and(ok, eq(size, 0x20)) { + returndatacopy(0, 0, 0x20) + count := mload(0) + } + } + return ok && size == 32 && count == 0; + } + + function _transfer(address receiver, uint256 amount) internal { + if (amount == 0) return; + (bool success,) = receiver.call{value: amount}(""); + require(success, "ETH transfer failed"); + } + + uint256[50] private __gap; +} diff --git a/contracts/contracts/l1/staking/IL1Staking.sol b/contracts/contracts/l1/staking/IL1Staking.sol deleted file mode 100644 index ba4f6801b..000000000 --- a/contracts/contracts/l1/staking/IL1Staking.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -interface IL1Staking { - /********** - * Events * - **********/ - - /// @notice staker registered - /// @param addr staker address - /// @param tmKey tendermint pubkey - /// @param blsKey BLS pubkey - event Registered(address addr, bytes32 tmKey, bytes blsKey); - - /// @notice stakers removed - /// @param stakers stakers removed - event StakersRemoved(address[] stakers); - - /// @notice Withdrawn - /// @param addr staker address - /// @param unlockHeight unlock block height - event Withdrawn(address indexed addr, uint256 unlockHeight); - - /// @notice staker claimed - /// @param staker staker claimed - /// @param receiver receiver address - event Claimed(address indexed staker, address receiver); - - /// @notice stakers were slashed - /// @param stakers slashed stakers - event Slashed(address[] stakers); - - /// @notice slash remaining claimed - /// @param receiver receiver address - /// @param amount claimed amount - event SlashRemainingClaimed(address receiver, uint256 amount); - - /// @notice whitelist updated - /// @param add addresses added - /// @param remove addresses removed - event WhitelistUpdated(address[] add, address[] remove); - - /// @notice staking value updated - /// @param oldStakingValue old staking value - /// @param newStakingValue new staking value - event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue); - - /// @notice gas limit add staker updated - /// @param oldGasLimit old gas limit - /// @param newGasLimit new gas limit - event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit); - - /// @notice gas limit remove stakers updated - /// @param oldGasLimit old gas limit - /// @param newGasLimit new gas limit - event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit); - - /// @notice reward percentage updated - /// @param oldPercentage old percentage - /// @param newPercentage new percentage - event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage); - - /// @notice challenge deposit value updated - /// @param oldChallengeDeposit old challengeDeposit - /// @param newChallengeDeposit new challengeDeposit - event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit); - - /************************* - * Public View Functions * - *************************/ - - /// @notice return all stakers - function getStakers() external view returns (address[255] memory); - - /// @notice return active stakers - function getActiveStakers() external view returns (address[] memory); - - /// @notice return staking value - function stakingValue() external view returns (uint256); - - /// @notice return challenge deposit value - function challengeDeposit() external view returns (uint256); - - /// @notice whether address is staker - /// @param addr the address to check - function isStaker(address addr) external view returns (bool); - - /// @notice whether address is active staker - /// @param addr the address to check - function isActiveStaker(address addr) external view returns (bool); - - /// @notice get staker bitmap - /// @param staker the staker address - function getStakerBitmap(address staker) external view returns (uint256); - - /// @notice get stakers bitmap - /// @param stakers the staker address array - function getStakersBitmap(address[] calldata stakers) external view returns (uint256); - - /// @notice verify BLS signature - /// @param signedSequencersBitmap bitmap of signed sequencers - /// @param sequencerSet sequencer set - /// @param msgHash bls message hash - /// @param signature batch signature - function verifySignature( - uint256 signedSequencersBitmap, - address[] calldata sequencerSet, - bytes32 msgHash, - bytes calldata signature - ) external view returns (bool); - - /***************************** - * Public Mutating Functions * - *****************************/ - - /// @notice challenger win, slash sequencers - /// @param sequencersBitmap the sequencers to slash - function slash(uint256 sequencersBitmap) external returns (uint256); -} diff --git a/contracts/contracts/l1/staking/L1Staking.sol b/contracts/contracts/l1/staking/L1Staking.sol deleted file mode 100644 index 165fec18d..000000000 --- a/contracts/contracts/l1/staking/L1Staking.sol +++ /dev/null @@ -1,515 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; - -import {Predeploys} from "../../libraries/constants/Predeploys.sol"; -import {Types} from "../../libraries/common/Types.sol"; -import {Staking} from "../../libraries/staking/Staking.sol"; -import {IL1Staking} from "./IL1Staking.sol"; -import {IL2Staking} from "../../l2/staking/IL2Staking.sol"; - -contract L1Staking is IL1Staking, Staking, OwnableUpgradeable, ReentrancyGuardUpgradeable { - /************* - * Variables * - *************/ - - /// @notice rollup Contract - address public rollupContract; - - /// @notice staking value - uint256 public stakingValue; - - /// @notice exit lock blocks - uint256 public withdrawalLockBlocks; - - /// @notice percentage awarded to challenger - uint256 public rewardPercentage; - - /// @notice cross-chain gas limit add staker - uint256 public gasLimitAddStaker; - - /// @notice cross-chain gas limit remove stakers - uint256 public gasLimitRemoveStakers; - - /// @notice slash remaining - uint256 public slashRemaining; - - /// @notice staker whitelist - mapping(address stakerAddr => bool inWhitelist) public whitelist; - - /// @notice staker removed list - mapping(address stakerAddr => bool removed) public removedList; - - /// @notice all stakers (0-254) - address[255] public stakerSet; - - /// @notice all stakers indexes (1-255). '0' means not exist. stakerIndexes[1] releated to stakerSet[0] - mapping(address stakerAddr => uint8 index) public stakerIndexes; - - /// @notice stakers to delete - address[] public deleteList; - - /// @notice staker deleteable height - mapping(address stakerAddr => uint256 height) public deleteableHeight; - - /// @notice all stakers info - mapping(address stakerAddr => Types.StakerInfo) public stakers; - - /// @notice bls key map - mapping(bytes blsPubkey => bool exist) public blsKeys; - - /// @notice tendermint key map - mapping(bytes32 tmPubkey => bool exist) public tmKeys; - - /// @notice withdraw unlock block height - mapping(address staker => uint256 amount) public withdrawals; - - /// @notice challenge deposit value - uint256 public challengeDeposit; - - /********************** - * Function Modifiers * - **********************/ - - /// @notice whether in whitelist - modifier inWhitelist(address addr) { - require(whitelist[addr], "not in whitelist"); - _; - } - - /// @notice only rollup contract - modifier onlyRollupContract() { - require(_msgSender() == rollupContract, "only rollup contract"); - _; - } - - /*************** - * Constructor * - ***************/ - - /// @param _messenger Address of CrossDomainMessenger on this network. - constructor(address payable _messenger) Staking(_messenger, payable(Predeploys.L2_STAKING)) { - _disableInitializers(); - } - - /*************** - * Initializer * - ***************/ - - /// @notice initializer - /// @param _rollupContract rollup contract address - /// @param _stakingValue staking value - /// @param _challengeDeposit challenge deposit value - /// @param _lockBlocks withdraw lock blocks - /// @param _rewardPercentage percentage awarded to challenger - /// @param _gasLimitAdd cross-chain gas limit add staker - /// @param _gasLimitRemove cross-chain gas limit remove stakers - function initialize( - address _rollupContract, - uint256 _stakingValue, - uint256 _challengeDeposit, - uint256 _lockBlocks, - uint256 _rewardPercentage, - uint256 _gasLimitAdd, - uint256 _gasLimitRemove - ) public initializer { - require(_rollupContract != address(0), "invalid rollup contract"); - require(_stakingValue > 0, "invalid staking value"); - require(_challengeDeposit > 0, "invalid challenge deposit value"); - require(_lockBlocks > 0, "invalid withdrawal lock blocks"); - require(_gasLimitAdd > 0, "invalid gas limit add staker"); - require(_gasLimitRemove > 0, "invalid gas limit remove stakers"); - require(_rewardPercentage > 0 && _rewardPercentage <= 100, "invalid challenger reward percentage"); - - __Ownable_init(); - __ReentrancyGuard_init(); - - rollupContract = _rollupContract; - rewardPercentage = _rewardPercentage; - stakingValue = _stakingValue; - challengeDeposit = _challengeDeposit; - withdrawalLockBlocks = _lockBlocks; - gasLimitAddStaker = _gasLimitAdd; - gasLimitRemoveStakers = _gasLimitRemove; - - emit GasLimitAddStakerUpdated(0, _gasLimitAdd); - emit GasLimitRemoveStakersUpdated(0, _gasLimitRemove); - emit RewardPercentageUpdated(0, _rewardPercentage); - } - - /************************ - * Restricted Functions * - ************************/ - - /// @notice update whitelist - function updateWhitelist(address[] calldata add, address[] calldata remove) external onlyOwner { - for (uint256 i = 0; i < add.length; i++) { - require(!removedList[add[i]], "in removed list"); - whitelist[add[i]] = true; - } - for (uint256 i = 0; i < remove.length; i++) { - delete whitelist[remove[i]]; - } - emit WhitelistUpdated(add, remove); - } - - /// @notice register staker - /// @param tmKey tendermint pubkey - /// @param blsKey bls pubkey - function register(bytes32 tmKey, bytes memory blsKey) external payable inWhitelist(_msgSender()) { - require(stakers[_msgSender()].addr == address(0), "already registered"); - require(tmKey != 0 && !tmKeys[tmKey], "invalid tendermint pubkey"); - require(blsKey.length == 256 && !blsKeys[blsKey], "invalid bls pubkey"); - require(msg.value == stakingValue, "invalid staking value"); - - stakers[_msgSender()] = Types.StakerInfo(_msgSender(), tmKey, blsKey); - _addStaker(_msgSender()); - blsKeys[blsKey] = true; - tmKeys[tmKey] = true; - emit Registered(_msgSender(), tmKey, blsKey); - - // send message to add staker on l2 - _msgAddStaker(stakers[_msgSender()]); - } - - /// @notice remove staker - function removeStaker(address[] memory _stakers) external onlyOwner { - for (uint256 i = 0; i < _stakers.length; i++) { - require(isActiveStaker(_stakers[i]), "only active staker can be removed"); - require(withdrawals[_stakers[i]] == 0, "withdrawing"); - - withdrawals[_stakers[i]] = block.number + withdrawalLockBlocks; - _removeStaker(_stakers[i]); - emit Withdrawn(_stakers[i], withdrawals[_stakers[i]]); - - delete whitelist[_stakers[i]]; - removedList[_stakers[i]] = true; - } - emit StakersRemoved(_stakers); - - // send message to remove stakers on l2 - _msgRemoveStakers(_stakers); - } - - /// @notice withdraw staking - function withdraw() external { - require(isActiveStaker(_msgSender()), "only active staker"); - require(withdrawals[_msgSender()] == 0, "withdrawing"); - - withdrawals[_msgSender()] = block.number + withdrawalLockBlocks; - _removeStaker(_msgSender()); - emit Withdrawn(_msgSender(), withdrawals[_msgSender()]); - - delete whitelist[_msgSender()]; - removedList[_msgSender()] = true; - - address[] memory remove = new address[](1); - remove[0] = _msgSender(); - emit StakersRemoved(remove); - - // send message to remove staker on l2 - _msgRemoveStakers(remove); - } - - /// @notice challenger win, slash sequencers - function slash(uint256 sequencersBitmap) external onlyRollupContract nonReentrant returns (uint256) { - address[] memory sequencers = getStakersFromBitmap(sequencersBitmap); - - uint256 valueSum; - for (uint256 i = 0; i < sequencers.length; i++) { - if (withdrawals[sequencers[i]] > 0) { - delete withdrawals[sequencers[i]]; - valueSum += stakingValue; - } else if (!isStakerInDeleteList(sequencers[i])) { - // If it is the first time to be slashed - valueSum += stakingValue; - _removeStaker(sequencers[i]); - // remove from whitelist - delete whitelist[sequencers[i]]; - removedList[sequencers[i]] = true; - } - } - - uint256 reward = (valueSum * rewardPercentage) / 100; - slashRemaining += valueSum - reward; - _transfer(rollupContract, reward); - - emit Slashed(sequencers); - emit StakersRemoved(sequencers); - - // send message to remove stakers on l2 - _msgRemoveStakers(sequencers); - - return reward; - } - - /// @notice claim slash remaining - /// @param receiver receiver address - function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { - uint256 _slashRemaining = slashRemaining; - _transfer(receiver, slashRemaining); - slashRemaining = 0; - emit SlashRemainingClaimed(receiver, _slashRemaining); - } - - /// @notice update staking value - /// @param _stakingValue staking value - function updateStakingValue(uint256 _stakingValue) external onlyOwner { - require(_stakingValue > 0 && _stakingValue != stakingValue, "invalid staking value"); - uint256 _oldStakingValue = stakingValue; - stakingValue = _stakingValue; - emit StakingValueUpdated(_oldStakingValue, stakingValue); - } - - /// @notice update gas limit of add staker - /// @param _gasLimitAdd cross-chain gas limit add staker - function updateGasLimitAddStaker(uint256 _gasLimitAdd) external onlyOwner { - require(_gasLimitAdd > 0 && _gasLimitAdd != gasLimitAddStaker, "invalid new gas limit"); - uint256 _oldGasLimitAddStaker = gasLimitAddStaker; - gasLimitAddStaker = _gasLimitAdd; - emit GasLimitAddStakerUpdated(_oldGasLimitAddStaker, _gasLimitAdd); - } - - /// @notice update gas limit of remove stakers - /// @param _gasLimitRemove cross-chain gas limit remove stakers - function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) external onlyOwner { - require(_gasLimitRemove > 0 && _gasLimitRemove != gasLimitRemoveStakers, "invalid new gas limit"); - uint256 _oldGasLimitRemove = gasLimitRemoveStakers; - gasLimitRemoveStakers = _gasLimitRemove; - emit GasLimitRemoveStakersUpdated(_oldGasLimitRemove, _gasLimitRemove); - } - - /// @notice update challenge deposit - /// @param _challengeDeposit challenge deposit value - function updateChallengeDeposit(uint256 _challengeDeposit) external onlyOwner { - require(_challengeDeposit > 0 && _challengeDeposit != challengeDeposit, "invalid challenge deposit value"); - uint256 _oldChallengeDeposit = challengeDeposit; - challengeDeposit = _challengeDeposit; - emit ChallengeDepositUpdated(_oldChallengeDeposit, _challengeDeposit); - } - - /// @notice update reward percentage - /// @param _rewardPercentage percentage awarded to challenger - function updateRewardPercentage(uint256 _rewardPercentage) external onlyOwner { - require( - _rewardPercentage > 0 && _rewardPercentage <= 100 && _rewardPercentage != rewardPercentage, - "invalid reward percentage" - ); - uint256 _oldRewardPercentage = rewardPercentage; - rewardPercentage = _rewardPercentage; - emit RewardPercentageUpdated(_oldRewardPercentage, _rewardPercentage); - } - - /// @notice clean staker store - function cleanStakerStore() external onlyOwner { - _cleanStakerStore(); - } - - /***************************** - * Public Mutating Functions * - *****************************/ - - /// @notice claim withdrawal - /// @param receiver receiver address - function claimWithdrawal(address receiver) external nonReentrant { - require(withdrawals[_msgSender()] > 0, "withdrawal not exist"); - require(withdrawals[_msgSender()] <= block.number, "withdrawal locked"); - - delete withdrawals[_msgSender()]; - _cleanStakerStore(); - - emit Claimed(_msgSender(), receiver); - - _transfer(receiver, stakingValue); - } - - /************************* - * Public View Functions * - *************************/ - - /// @notice verify BLS signature - function verifySignature( - uint256, // signedSequencersBitmap - address[] calldata, // sequencerSet - bytes32, // msgHash - bytes calldata // signature - ) external pure returns (bool) { - // TODO verify BLS signature - return true; - } - - /// @notice return all stakers - function getStakers() external view returns (address[255] memory) { - return stakerSet; - } - - /// @notice return active stakers - function getActiveStakers() external view returns (address[] memory) { - uint256 activeStakersNumber; - bool[] memory tags = new bool[](255); - for (uint256 i = 0; i < 255; i++) { - // valid address and not in delete list - if (stakerSet[i] != address(0) && deleteableHeight[stakerSet[i]] == 0) { - activeStakersNumber++; - tags[i] = true; - } - } - address[] memory activeStakers = new address[](activeStakersNumber); - uint256 index; - for (uint256 i = 0; i < 255; i++) { - if (tags[i]) { - activeStakers[index] = stakerSet[i]; - index++; - } - } - return activeStakers; - } - - /// @notice whether address is staker - /// @param addr address to check - function isStaker(address addr) public view returns (bool) { - if (stakerIndexes[addr] == 0) { - return false; - } - return stakerSet[stakerIndexes[addr] - 1] == addr; - } - - /// @notice whether address is active staker - /// @param addr address to check - function isActiveStaker(address addr) public view returns (bool) { - if (stakerIndexes[addr] == 0) { - return false; - } - return (stakerSet[stakerIndexes[addr] - 1] == addr) && (deleteableHeight[addr] == 0); - } - - /// @notice whether address in delete list - /// @param addr address to check - function isStakerInDeleteList(address addr) public view returns (bool) { - return deleteableHeight[addr] > 0; - } - - /// @notice get staker bitmap - /// @param _staker the staker address - function getStakerBitmap(address _staker) external view returns (uint256 bitmap) { - require(isStaker(_staker), "invalid staker"); - bitmap = 1 << stakerIndexes[_staker]; - return bitmap; - } - - /// @notice get stakers bitmap - /// @param _stakers the staker address array - function getStakersBitmap(address[] calldata _stakers) external view returns (uint256 bitmap) { - require(_stakers.length <= 255, "stakers length out of bounds"); - for (uint256 i = 0; i < _stakers.length; i++) { - require(isStaker(_stakers[i]), "invalid staker"); - bitmap = bitmap | (1 << stakerIndexes[_stakers[i]]); - } - return bitmap; - } - - /// @notice get stakers from bitmap - /// @param bitmap the stakers bitmap - function getStakersFromBitmap(uint256 bitmap) public view returns (address[] memory stakerAddrs) { - // skip first bit - uint256 _bitmap = bitmap >> 1; - uint256 stakersLength = 0; - while (_bitmap > 0) { - stakersLength = stakersLength + 1; - _bitmap = _bitmap & (_bitmap - 1); - } - - stakerAddrs = new address[](stakersLength); - uint256 index = 0; - for (uint8 i = 1; i <= 255; i++) { - if ((bitmap & (1 << i)) > 0) { - stakerAddrs[index] = stakerSet[i - 1]; - index = index + 1; - if (index >= stakersLength) { - break; - } - } - } - } - - /********************** - * Internal Functions * - **********************/ - - /// @notice add stater - /// @param addr staker address - function _addStaker(address addr) internal { - for (uint8 i = 0; i < 255; i++) { - if (stakerSet[i] == address(0)) { - stakerSet[i] = addr; - stakerIndexes[addr] = i + 1; - return; - } - } - require(false, "slot full"); - } - - /// @notice Add staker to deleteList, it will not be actually deleted until cleanStakerStore is executed - /// @param addr staker address - function _removeStaker(address addr) internal { - require(deleteableHeight[addr] == 0, "already in deleteList"); - deleteList.push(addr); - deleteableHeight[addr] = block.number + withdrawalLockBlocks; - } - - /// @notice transfer ETH - /// @param _to The address to transfer ETH to. - /// @param _amount The amount of ETH to transfer. - function _transfer(address _to, uint256 _amount) internal { - if (_amount > 0) { - (bool success, ) = _to.call{value: _amount}(""); - require(success, "Rollup: ETH transfer failed"); - } - } - - /// @notice add staker - /// @param add staker to add - function _msgAddStaker(Types.StakerInfo memory add) internal { - MESSENGER.sendMessage( - address(OTHER_STAKING), - 0, - abi.encodeCall(IL2Staking.addStaker, (add)), - gasLimitAddStaker - ); - } - - /// @notice remove stakers - /// @param remove stakers to remove - function _msgRemoveStakers(address[] memory remove) internal { - MESSENGER.sendMessage( - address(OTHER_STAKING), - 0, - abi.encodeCall(IL2Staking.removeStakers, (remove)), - gasLimitRemoveStakers - ); - } - - /// @notice clean staker store - function _cleanStakerStore() internal { - uint256 i = 0; - while (i < deleteList.length) { - if (deleteableHeight[deleteList[i]] <= block.number) { - // clean stakerSet - delete stakerSet[stakerIndexes[deleteList[i]] - 1]; - delete stakerIndexes[deleteList[i]]; - - // clean staker info - delete stakers[deleteList[i]]; - - // clean deleteList - delete deleteableHeight[deleteList[i]]; - deleteList[i] = deleteList[deleteList.length - 1]; - deleteList.pop(); - } else { - i++; - } - } - } -} diff --git a/contracts/contracts/test/L1Staking.t.sol b/contracts/contracts/test/L1Staking.t.sol deleted file mode 100644 index 825e5040f..000000000 --- a/contracts/contracts/test/L1Staking.t.sol +++ /dev/null @@ -1,1154 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; - -import {Predeploys} from "../libraries/constants/Predeploys.sol"; -import {Types} from "../libraries/common/Types.sol"; -import {IL1Staking} from "../l1/staking/IL1Staking.sol"; -import {L1Staking} from "../l1/staking/L1Staking.sol"; -import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; - -// import "forge-std/console.sol"; - -contract StakingInitializeTest is L1MessageBaseTest { - function test_initialize_initializeAgain_revert() external { - // verify the initialize only can be called once. - hevm.expectRevert("Initializable: contract is already initialized"); - l1Staking.initialize( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ); - } - - function test_initialize_rollupZeroAddress_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid rollup contract. - hevm.expectRevert("invalid rollup contract"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(0), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_stakingValueEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid staking value. - hevm.expectRevert("invalid staking value"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - 0, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_challengeDepositEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid staking value. - hevm.expectRevert("invalid challenge deposit value"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, 0, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, defaultGasLimitRemove) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_lockBlocksEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid withdrawal lock blocks. - hevm.expectRevert("invalid withdrawal lock blocks"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - 0, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_gasLimitAddEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid gas limit add staker. - hevm.expectRevert("invalid gas limit add staker"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, 0, defaultGasLimitRemove) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_gasLimitRemoveEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid gas limit remove stakers. - hevm.expectRevert("invalid gas limit remove stakers"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, 0) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_rewardPercentageEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid challenger reward percentage. - hevm.expectRevert("invalid challenger reward percentage"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - 0, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_rewardPercentageEq101_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid challenger reward percentage. - hevm.expectRevert("invalid challenger reward percentage"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - 101, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_succeeds() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Verify the GasLimitAddStakerUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.GasLimitAddStakerUpdated(0, 22); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.GasLimitRemoveStakersUpdated(0, 33); - - // Verify the RewardPercentageUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.RewardPercentageUpdated(0, 11); - - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, 11, 22, 33) - ) - ); - hevm.stopPrank(); - } -} - -contract StakingTest is L1MessageBaseTest { - function test_setUpCheck_succeeds() external { - assertEq(rollup.l1StakingContract(), address(l1Staking)); - assertEq(address(l1Staking.OTHER_STAKING()), address(Predeploys.L2_STAKING)); - assertEq(address(l1Staking.MESSENGER()), address(l1CrossDomainMessenger)); - assertEq(l1Staking.rollupContract(), address(rollup)); - assertEq(l1Staking.stakingValue(), STAKING_VALUE); - assertEq(l1Staking.withdrawalLockBlocks(), LOCK_BLOCKS); - assertEq(l1Staking.rewardPercentage(), rewardPercentage); - assertEq(l1Staking.gasLimitAddStaker(), 1000000); - assertEq(l1Staking.gasLimitRemoveStakers(), 10000000); - } - - function test_invalidStaker_reverts() external { - // make param - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - hevm.startPrank(address(emptyContract)); - hevm.expectRevert("invalid staker"); - l1Staking.getStakersBitmap(sequencers); - hevm.stopPrank(); - } - - function test_registerAlice_succeeds() external { - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(alice); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); - } - - function test_stakerWithdrawAndClaim_succeeds() external { - // register - - hevm.deal(bob, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(bob); - address[] memory add = new address[](1); - add[0] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(bob); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(bob, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(bob); - assertEq(addrCheck, bob); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); - - // withdraw - - hevm.prank(bob); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Withdrawn(bob, block.number + LOCK_BLOCKS); - l1Staking.withdraw(); - assertFalse(l1Staking.whitelist(bob)); - assertTrue(l1Staking.isStaker(bob)); - assertTrue(l1Staking.isStakerInDeleteList(bob)); - assertTrue(l1Staking.removedList(bob)); - assertEq(l1Staking.withdrawals(bob), block.number + LOCK_BLOCKS); - hevm.stopPrank(); - - // claim - - hevm.prank(bob); - assertEq(bob.balance, 4 * STAKING_VALUE); - hevm.roll(block.number + LOCK_BLOCKS + 1); - l1Staking.claimWithdrawal(bob); - assertEq(bob.balance, 5 * STAKING_VALUE); - assertEq(l1Staking.withdrawals(bob), 0); - hevm.stopPrank(); - } - - function test_stakersBitmap_succeeds() external { - address[] memory stakersAddr = new address[](255); - for (uint256 i = 0; i < 255; i++) { - stakersAddr[i] = address(bytes20(bytes32(keccak256(abi.encodePacked(1500 + i))))); - hevm.deal(stakersAddr[i], 5 * STAKING_VALUE); - } - hevm.prank(multisig); - l1Staking.updateWhitelist(stakersAddr, new address[](0)); - - for (uint256 i = 0; i < 255; i++) { - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(stakersAddr[i]); - hevm.startPrank(stakersAddr[i]); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - hevm.stopPrank(); - } - - uint256 bitmap = l1Staking.getStakersBitmap(stakersAddr); - address[] memory stakersConvert = l1Staking.getStakersFromBitmap(bitmap); - assertEq(stakersAddr.length, stakersConvert.length); - assertEq(stakersAddr[0], stakersConvert[0]); - assertEq(stakersAddr[stakersAddr.length - 1], stakersConvert[stakersConvert.length - 1]); - - // console.logString("......................"); - // console.logUint(bitmap); - // console.logUint(stakersAddr.length); - // console.logUint(stakersConvert.length); - // console.logString("......................"); - } - - function test_slash_succeeds() external { - // TODO - } - - function test_updateParams_succeeds() external { - // TODO - } -} - -contract StakingWhitelistTest is L1MessageBaseTest { - function test_whitelist_notOwner_reverts() external { - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateWhitelist(add, new address[](0)); - } - - function test_whitelist_add_succeeds() external { - // make add param - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - - // Verify the WhitelistUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.WhitelistUpdated(add, new address[](0)); - - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - } - - function test_whitelist_remove_succeeds() external { - address[] memory add = new address[](1); - add[0] = alice; - address[] memory remove = new address[](1); - remove[0] = bob; - - // Verify the WhitelistUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.WhitelistUpdated(add, remove); - - hevm.prank(multisig); - l1Staking.updateWhitelist(add, remove); - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - } - - function test_whitelist_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_whitelist_reAdd_inRemovedList_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - - hevm.startPrank(multisig); - address[] memory reAdd = new address[](1); - reAdd[0] = bob; - hevm.expectRevert("in removed list"); - l1Staking.updateWhitelist(reAdd, new address[](0)); - hevm.stopPrank(); - } - - function test_whitelist_slash_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - assertEq(bitmap, 4); - address[] memory stakers = l1Staking.getStakersFromBitmap(bitmap); - assertEq(stakers.length, 1); - assertEq(stakers[0], bob); - hevm.prank(l1Staking.rollupContract()); - l1Staking.slash(bitmap); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } -} - -contract StakingRegisterTest is L1MessageBaseTest { - function test_register_notInWhitelist_reverts() external { - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("not in whitelist"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_alreadyRegistered_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - hevm.expectRevert("already registered"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notStakingValue_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid staking value"); - l1Staking.register{value: STAKING_VALUE - 1}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notTmKey_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid tendermint pubkey"); - l1Staking.register{value: STAKING_VALUE}(0, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notBlsKey_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid bls pubkey"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, ""); - hevm.stopPrank(); - } - - function test_register_succeeds() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - (address addressCheck, , ) = l1Staking.stakers(alice); - assertEq(addressCheck, address(0)); - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - assertFalse(l1Staking.blsKeys(aliceInfo.blsKey)); - assertFalse(l1Staking.tmKeys(aliceInfo.tmKey)); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, aliceInfo.tmKey); - assertBytesEq(blsKeyCheck, aliceInfo.blsKey); - assertTrue(l1Staking.blsKeys(aliceInfo.blsKey)); - assertTrue(l1Staking.tmKeys(aliceInfo.tmKey)); - } -} - -contract StakingWithdrawTest is L1MessageBaseTest { - function test_withdraw_notStaker_reverts() external { - // bob withdraw - hevm.expectRevert("only active staker"); - hevm.startPrank(bob); - l1Staking.withdraw(); - hevm.stopPrank(); - } - - function test_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // before withdraw - assertEq(l1Staking.withdrawals(bob), 0); - assertTrue(l1Staking.isStaker(bob)); - assertFalse(l1Staking.removedList(bob)); - - // Verify the StakersRemoved event is emitted successfully. - address[] memory remove = new address[](1); - remove[0] = bob; - hevm.expectEmit(true, true, true, true); - emit IL1Staking.StakersRemoved(remove); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // after withdraw - // check - assertEq(l1Staking.withdrawals(bob), block.number + l1Staking.withdrawalLockBlocks()); - assertTrue(l1Staking.isStaker(bob)); - assertTrue(l1Staking.isStakerInDeleteList(bob)); - - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } -} - -contract StakingRemoveStakerTest is L1MessageBaseTest { - // TODO -} - -contract StakingSlashTest is L1MessageBaseTest { - function test_slash_notRollup_reverts() external { - hevm.startPrank(address(emptyContract)); - hevm.expectRevert("only rollup contract"); - l1Staking.slash(0); - hevm.stopPrank(); - } - - function test_slash_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_slash_notWithdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_slash_all_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - uint256 beforeBalance = l1Staking.rollupContract().balance; - - // Verify the Slashed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Slashed(sequencers); - - // Verify the StakersRemoved event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.StakersRemoved(sequencers); - - // sequencer to slash - uint256 bitmap = l1Staking.getStakersBitmap(sequencers); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - uint256 afterBalance = l1Staking.rollupContract().balance; - assertEq(reward, afterBalance - beforeBalance); - } -} - -contract StakingClaimSlashRemainingTest is L1MessageBaseTest { - function test_claimSlashRemaining_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.claimSlashRemaining(bob); - } - - function test_claimSlashRemaining_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - uint256 beforeBalance = l1Staking.rollupContract().balance; - - // sequencer to slash - uint256 bitmap = l1Staking.getStakersBitmap(sequencers); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - uint256 afterBalance = l1Staking.rollupContract().balance; - assertEq(reward, afterBalance - beforeBalance); - - // Verify the SlashRemainingClaimed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.SlashRemainingClaimed(multisig, 2 * STAKING_VALUE - reward); - - uint256 beforeBalanceOfM = multisig.balance; - hevm.prank(multisig); - l1Staking.claimSlashRemaining(multisig); - uint256 afterBalanceOfM = multisig.balance; - emit log_uint(STAKING_VALUE * 2); - emit log_uint(afterBalanceOfM - beforeBalanceOfM); - emit log_uint(reward); - uint256 remaining = 2 * STAKING_VALUE - reward; - assertEq(afterBalanceOfM - beforeBalanceOfM, remaining); - } -} - -contract StakingUpdateGasLimitAddStakerTest is L1MessageBaseTest { - function test_updateGasLimitAddStaker_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateGasLimitAddStaker(0); - } - - function test_updateGasLimitAddStaker_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitAddStaker(0); - // defaultGasLimitAdd - } - - function test_updateGasLimitAddStaker_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitAddStaker(defaultGasLimitAdd); - } - - function test_updateGasLimitAddStaker_succeeds() external { - uint256 newValue = defaultGasLimitAdd / 10; - uint256 oldValue = l1Staking.gasLimitAddStaker(); - - // Verify the GasLimitAddStakerUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.GasLimitAddStakerUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateGasLimitAddStaker(newValue); - assertEq(l1Staking.gasLimitAddStaker(), newValue); - } -} - -contract StakingUpdateGasLimitRemoveStakersTest is L1MessageBaseTest { - function test_updateGasLimitRemoveStakers_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateGasLimitRemoveStakers(0); - } - - function test_updateGasLimitRemoveStakers_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitRemoveStakers(0); - } - - function test_updateGasLimitRemoveStakers_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitRemoveStakers(defaultGasLimitRemove); - } - - function test_updateGasLimitRemoveStakers_succeeds() external { - uint256 newValue = defaultGasLimitRemove / 10; - uint256 oldValue = l1Staking.gasLimitRemoveStakers(); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.GasLimitRemoveStakersUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateGasLimitRemoveStakers(newValue); - assertEq(l1Staking.gasLimitRemoveStakers(), newValue); - } -} - -contract StakingUpdateRewardPercentageTest is L1MessageBaseTest { - function test_updateRewardPercentage_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateRewardPercentage(0); - } - - function test_updateRewardPercentage_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(0); - } - - function test_updateRewardPercentage_ge100_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(101); - } - - function test_updateRewardPercentage_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(rewardPercentage); - } - - function test_updateRewardPercentage_succeeds() external { - uint256 newValue = 66; - uint256 oldValue = l1Staking.rewardPercentage(); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.RewardPercentageUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateRewardPercentage(newValue); - assertEq(l1Staking.rewardPercentage(), newValue); - } -} - -contract StakingClaimWithdrawalTest is L1MessageBaseTest { - function test_claimWithdrawal_notWithdraw_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.expectRevert("withdrawal not exist"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_locked_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.expectRevert("withdrawal locked"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_eqLockedBlockNumber_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - - // set block number - hevm.roll(block.number + l1Staking.withdrawalLockBlocks() - 1); - hevm.expectRevert("withdrawal locked"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - - // Verify the Claimed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Claimed(bob, bob); - - // set block number - hevm.roll(block.number + l1Staking.withdrawalLockBlocks() + 1); - uint256 beforeBalance = bob.balance; - l1Staking.claimWithdrawal(bob); - uint256 afterBalance = bob.balance; - assertEq(afterBalance - beforeBalance, STAKING_VALUE); - hevm.stopPrank(); - } -} - -contract StakingVerifySignatureTest is L1MessageBaseTest { - // function testVerifySignature() external { - // l1Staking.verifySignature(); - // } -} diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index dbcc95c1c..acc05e63e 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -2,12 +2,71 @@ pragma solidity =0.8.24; import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; -import {Types} from "../libraries/common/Types.sol"; import {IRollup} from "../l1/rollup/IRollup.sol"; -import {IL1Staking} from "../l1/staking/IL1Staking.sol"; +import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; import {BatchHeaderCodecV0} from "../libraries/codec/BatchHeaderCodecV0.sol"; import {BatchHeaderCodecV1} from "../libraries/codec/BatchHeaderCodecV1.sol"; +contract SubmitterCandidateMock { + enum ReturnMode { + Normal, + RevertCall, + Short, + Long, + BadAddressEncoding + } + + address public declaredRollup; + uint256 public deposit; + uint256 public zeroAddressActive; + ReturnMode public returnMode; + + constructor(address rollup_, uint256 deposit_, uint256 zeroAddressActive_) { + declaredRollup = rollup_; + deposit = deposit_; + zeroAddressActive = zeroAddressActive_; + } + + function setReturnMode(ReturnMode mode) external { + returnMode = mode; + } + + fallback() external { + ReturnMode mode = returnMode; + if (mode == ReturnMode.RevertCall) revert("candidate reverted"); + + uint256 value; + if (msg.sig == ISubmitter.rollupContract.selector) { + value = uint160(declaredRollup); + if (mode == ReturnMode.BadAddressEncoding) value |= uint256(1) << 200; + } else if (msg.sig == ISubmitter.isActive.selector) { + value = zeroAddressActive; + } else if (msg.sig == ISubmitter.challengeDeposit.selector) { + value = deposit; + } else { + revert("unknown selector"); + } + + assembly { + mstore(0, value) + } + if (mode == ReturnMode.Short) { + assembly { + return(0, 31) + } + } + if (mode == ReturnMode.Long) { + assembly { + mstore(32, 1) + return(0, 64) + } + } + assembly { + return(0, 32) + } + } +} + contract RollupCommitBatchWithProofTest is L1MessageBaseTest { /// @dev Test contract for commitBatchWithProof function /// This function allows permissionless batch submission when sequencers are stalled. @@ -15,17 +74,11 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { bytes public batchHeader0; bytes32 public batchHash0; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); // Setup batch signature input - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); // Import genesis batch bytes memory _batchHeader0 = new bytes(249); @@ -45,23 +98,15 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { rollup.importGenesisBatch(batchHeader0); batchHash0 = rollup.committedBatches(0); - // Setup staker - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory addrs = new address[](1); - addrs[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(addrs, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + _registerAndStakeSubmitter(alice); // Set rollupDelayPeriod (e.g., 1 hour) - no prank needed for hevm.store hevm.store(address(rollup), bytes32(ROLLUP_DELAY_PERIOD_SLOT), bytes32(uint256(3600))); } /// @dev Helper to compute sequencerSetVerifyHash from sequencerSets - function _getSequencerSetVerifyHash() internal view returns (bytes32) { - return keccak256(batchSignatureInput.sequencerSets); + function _getSequencerSetVerifyHash() internal pure returns (bytes32) { + return bytes32(0); } /// @dev Helper to create batch header that matches what _commitBatchWithBatchData produces @@ -142,7 +187,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid timing"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -171,7 +215,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid version"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -198,7 +241,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("V2 requires at least 1 blob"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -226,7 +268,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("Pausable: paused"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -254,7 +295,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("previous state root is zero"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -282,7 +322,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("new state root is zero"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -315,7 +354,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect parent batch hash"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -343,7 +381,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect previous state root"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -376,7 +413,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -417,7 +453,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -451,7 +486,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, mockProof ); @@ -486,7 +520,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -542,7 +575,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("l1msg delay"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -575,7 +607,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(bob); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -626,7 +657,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -661,7 +691,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -680,16 +709,10 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { contract RollupCommitBatchTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); } function test_commitAndFinalizeWithL1Messages_succeeds() public { @@ -756,27 +779,17 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 153)), bytesData3) // withdrawRootHash mstore( add(batchHeader1, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 + 0 ) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash } uint64 lastBlockNumber = 1; uint16 numL1Messages = 1; - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), - abi.encode(true) - ); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), - abi.encode(2) - ); _setupDelayAndWarpForProof(); _mockVerifierForProof(); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); + emit IRollup.CommitBatch(1, keccak256(batchHeader1)); batchDataInput = IRollup.BatchDataInput( 0, batchHeader0, @@ -786,12 +799,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData3 ); - rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader1, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchHeader1, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(1)); bytes32 batchHash1 = rollup.committedBatches(1); - assertEq(batchHash1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); + assertEq(batchHash1, keccak256(batchHeader1)); bytes32 stateRoot1 = rollup.committedStateRoots(1); assertEq(stateRoot1, bytesData1); @@ -828,26 +841,15 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader2, add(0x20, 153)), bytesData4) // withdrawRootHash mstore( add(batchHeader2, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 + 0 ) // sequencerSetVerifyHash mstore(add(batchHeader2, add(0x20, 217)), batchHash1) // parentBatchHash mstore(add(batchHeader2, add(0x20, 249)), shl(192, lastBlockNumber)) // lastBlockNumber } - hevm.prank(multisig); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), - abi.encode(true) - ); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), - abi.encode(2) - ); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); + emit IRollup.CommitBatch(2, keccak256(batchHeader2)); batchDataInput = IRollup.BatchDataInput( 1, @@ -858,12 +860,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData4 ); - rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader2, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchHeader2, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(2)); bytes32 batchHash2 = rollup.committedBatches(2); - assertEq(batchHash2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); + assertEq(batchHash2, keccak256(batchHeader2)); bytes32 stateRoot2 = rollup.committedStateRoots(2); assertEq(stateRoot2, bytesData1); @@ -889,36 +891,11 @@ contract RollupTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - // add staker - - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(alice); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); + _registerAndStakeSubmitter(alice); } function test_commitBatches_succeeds() external { @@ -940,66 +917,19 @@ contract RollupTest is L1MessageBaseTest { } hevm.prank(multisig); rollup.importGenesisBatch(batchHeader0); - // only active staker allowed, revert + // only active submitter allowed, revert hevm.startPrank(address(0)); - hevm.expectRevert("only active staker allowed"); + hevm.expectRevert("only active submitter allowed"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); - // invalid version, revert (version 3+ is invalid; version 2 is now valid V2 multi-blob) + // The official path is structurally fresh-blob only. This Foundry version cannot + // attach a blob sidecar, so validation after the blob gate is covered by withProof. hevm.startPrank(alice); - hevm.expectRevert("invalid version"); - batchDataInput = IRollup.BatchDataInput(3, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); - hevm.stopPrank(); - - // batch header length incorrect, revert - hevm.startPrank(alice); - hevm.expectRevert("batch header length too small"); - batchDataInput = IRollup.BatchDataInput(0, new bytes(120), 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); - hevm.stopPrank(); - - // incorrect batch index, revert - assembly { - mstore(add(batchHeader0, add(0x20, 1)), shl(192, 1)) // change batch index to 1 - } - hevm.startPrank(alice); - hevm.expectRevert("incorrect batch index"); + hevm.expectRevert("must carry blob"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); - hevm.stopPrank(); - assembly { - mstore(add(batchHeader0, add(0x20, 1)), 0) // change back - } - - // incorrect parent batch hash, revert - assembly { - mstore(add(batchHeader0, add(0x20, 25)), 2) // change data hash for batch0 - } - hevm.startPrank(alice); - hevm.expectRevert("incorrect parent batch hash"); - batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); - hevm.stopPrank(); - assembly { - mstore(add(batchHeader0, add(0x20, 25)), 1) // change back - mstore(add(batchHeader0, add(0x20, 57)), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) - } - - // incorrect previous state root, revert - hevm.startPrank(alice); - hevm.expectRevert("incorrect previous state root"); - batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, bytes32(uint256(2)), stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); - hevm.stopPrank(); - - // incorrect batch header length, revert - hevm.startPrank(alice); - hevm.expectRevert("batch header length too small"); - batchDataInput = IRollup.BatchDataInput(0, new bytes(248), 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // commit batch with one chunk, no tx, correctly (commitBatch requires blob when no stored hash; use commitBatchWithProof) @@ -1014,7 +944,7 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, getTreeRoot(), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), rollup.committedBatches(0) ); hevm.startPrank(alice); @@ -1022,18 +952,17 @@ contract RollupTest is L1MessageBaseTest { hevm.deal(address(0), 10 ether); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); hevm.stopPrank(); assertGt(uint256(rollup.committedBatches(1)), 0); - // batch is already committed, revert (commitBatch also reverts with "commitBatch requires no stored blob hash" when slot is set) + // The fresh-blob gate remains first even if the target index is already occupied. hevm.startPrank(alice); - hevm.expectRevert("commitBatch requires no stored blob hash"); + hevm.expectRevert("must carry blob"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); } @@ -1071,19 +1000,18 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), batchHash0 ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); hevm.stopPrank(); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + assertEq(rollup.committedBatches(1), keccak256(batchHeader1ForProof)); // warp again so second commitBatchWithProof passes rollupDelay (batchDataStore[1].originTimestamp + period < block.timestamp) hevm.warp(block.timestamp + 3601); bytes memory batchHeader1 = new bytes(249); @@ -1099,7 +1027,7 @@ contract RollupTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 153)), bytesData4) // withdrawRootHash mstore( add(batchHeader1, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 + 0 ) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash mstore(add(batchHeader1, add(0x20, 249)), 0) // bitmap0 @@ -1115,14 +1043,13 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), rollup.committedBatches(1) ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader1, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader2ForProof, hex"deadbeef" ); @@ -1180,7 +1107,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("Pausable: paused"); batchDataInput = IRollup.BatchDataInput(0, new bytes(0), 0, 0, stateRoot, stateRoot, bytes32(uint256(4))); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.expectRevert("Pausable: paused"); rollup.finalizeBatch(new bytes(0)); @@ -1294,23 +1221,10 @@ contract RollupTest is L1MessageBaseTest { contract RollupCommitStateTest is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + _registerAndStakeSubmitter(alice); } function _genesisBatchHeader() internal pure returns (bytes memory batchHeader0) { @@ -1334,7 +1248,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), parentBatchHash ); } @@ -1353,7 +1267,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), bytesData1) mstore(add(batchHeader1, add(0x20, 121)), bytesData1) mstore(add(batchHeader1, add(0x20, 153)), bytesData4) - mstore(add(batchHeader1, add(0x20, 185)), 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067) + mstore(add(batchHeader1, add(0x20, 185)), 0) mstore(add(batchHeader1, add(0x20, 217)), parentBatchHash) mstore(add(batchHeader1, add(0x20, 249)), 0) } @@ -1373,7 +1287,6 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); @@ -1397,11 +1310,11 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + bytes32 expectedBatchHash = keccak256(batchHeader1ForProof); + assertEq(rollup.committedBatches(1), expectedBatchHash); assertGt(uint256(rollup.batchBlobVersionedHashes(1)), 0); // Revert batch 1 (blob hash is preserved) @@ -1415,8 +1328,8 @@ contract RollupCommitStateTest is L1MessageBaseTest { // Recommit with commitState (no blob in tx; uses stored blob hash) batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput, batchSignatureInput); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + rollup.commitState(batchDataInput); + assertEq(rollup.committedBatches(1), expectedBatchHash); assertEq(uint256(rollup.lastCommittedBatchIndex()), 1); } @@ -1428,7 +1341,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput, batchSignatureInput); + rollup.commitState(batchDataInput); // Without blob in tx, commitState succeeds. Revert "commitState must not carry blob" is hit only when blobhash(0) != 0 (blob tx). assertEq(rollup.lastCommittedBatchIndex(), 1); } @@ -1442,59 +1355,315 @@ contract RollupCommitStateTest is L1MessageBaseTest { batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); hevm.expectRevert("no stored blob hash for this batch"); - rollup.commitState(batchDataInput, batchSignatureInput); + rollup.commitState(batchDataInput); } /// @dev commitState can only be called by an active staker. - function test_commitState_only_active_staker() public { + function test_commitState_only_active_submitter() public { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(address(1)); - hevm.expectRevert("only active staker allowed"); - rollup.commitState(batchDataInput, batchSignatureInput); + hevm.expectRevert("only active submitter allowed"); + rollup.commitState(batchDataInput); } - /// @dev Mutual exclusion: (1) commitBatch reverts when stored blob hash exists; (2) commitState reverts when no stored hash (see test_commitState_reverts_when_no_stored_blob_hash). - function test_commitState_commitBatch_mutual_exclusion() public { + /// @dev commitBatch is fresh-blob only even when a stale stored hash exists. + function test_commitBatch_requires_blob_when_stored_hash_exists() public { bytes memory batchHeader0 = _genesisBatchHeader(); hevm.prank(multisig); rollup.importGenesisBatch(batchHeader0); - // When there IS stored blob hash for batch 1, commitBatch must revert + // A real blob transaction may overwrite this stale value; a no-blob call cannot. _setStoredBlobHash(1); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - hevm.expectRevert("commitBatch requires no stored blob hash"); - rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.expectRevert("must carry blob"); + rollup.commitBatch(batchDataInput); } } +contract RollupSubmitterCutoverTest is L1MessageBaseTest { + bytes32 internal constant ROOT_1 = bytes32(uint256(1)); + bytes32 internal constant ROOT_2 = bytes32(uint256(2)); + bytes32 internal constant ROOT_3 = bytes32(uint256(3)); + uint256 internal constant BATCH_DATA_STORE_SLOT = 162; + uint256 internal constant PENDING_BATCH_COUNT_SLOT = 174; + + function setUp() public virtual override { + super.setUp(); + _registerAndStakeSubmitter(alice); + _registerAndStakeSubmitter(bob); + } + + function test_currentSelectorsAreDistinctFromPreSubmitterSelectors() public { + assertEq(IRollup.commitBatch.selector, bytes4(0x41f756da)); + assertEq(IRollup.commitState.selector, bytes4(0x67caa37a)); + assertEq(IRollup.commitBatchWithProof.selector, bytes4(0x1544ba3a)); + assertTrue(IRollup.commitBatch.selector != bytes4(0x428868b5)); + assertTrue(IRollup.commitState.selector != bytes4(0x1e8825be)); + assertTrue(IRollup.commitBatchWithProof.selector != bytes4(0x4e8f1d67)); + } + + function test_liabilityReleasedExactlyByRevertAndFinalize() public { + bytes memory header0 = _importGenesis(); + bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); + bytes memory header2 = _commitStateAs(bob, header1, 2, ROOT_2, ROOT_3); + + assertEq(rollup.pendingBatchCount(alice), 1); + assertEq(rollup.pendingBatchCount(bob), 1); + (, , , address batch1Submitter) = rollup.batchDataStore(1); + (, , , address batch2Submitter) = rollup.batchDataStore(2); + assertEq(batch1Submitter, alice); + assertEq(batch2Submitter, bob); + + hevm.prank(multisig); + rollup.revertBatch(header2, 1); + assertEq(rollup.pendingBatchCount(alice), 1); + assertEq(rollup.pendingBatchCount(bob), 0); + + hevm.warp(block.timestamp + finalizationPeriodSeconds + 1); + rollup.finalizeBatch(header1); + assertEq(rollup.pendingBatchCount(alice), 0); + } + + function test_challengeAndSlashDoNotReleaseLiability() public { + bytes memory header0 = _importGenesis(); + bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); + bytes32 batchHash = rollup.committedBatches(1); + + hevm.prank(bob); + rollup.challengeState{value: CHALLENGE_DEPOSIT}(1, batchHash); + hevm.warp(block.timestamp + proofWindow + 1); + hevm.prank(alice); + rollup.proveState(header1, hex"01"); + + assertEq(rollup.pendingBatchCount(alice), 1); + assertEq(rollup.revertReqIndex(), 1); + assertEq(submitter.stakeOf(alice), 0); + + hevm.prank(multisig); + rollup.revertBatch(header1, 1); + assertEq(rollup.pendingBatchCount(alice), 0); + assertEq(rollup.revertReqIndex(), 0); + } + + function test_permissionlessProofUsesZeroSubmitterAndZeroHeaderField() public { + bytes memory header0 = _importGenesis(); + _setupDelayAndWarpForProof(); + _mockMessageQueueNotDelayedForProof(); + _mockVerifierForProof(); + + bytes memory header1 = _createBatchHeaderV0ForProof( + 1, + 0, + 0, + _computeDataHash(1, 0), + ROOT_1, + ROOT_2, + bytes32(uint256(101)), + bytes32(0), + rollup.committedBatches(0) + ); + IRollup.BatchDataInput memory input = IRollup.BatchDataInput( + 0, + header0, + 1, + 0, + ROOT_1, + ROOT_2, + bytes32(uint256(101)) + ); + + hevm.prank(address(0xBEEF)); + rollup.commitBatchWithProof(input, header1, hex"01"); + + (, , , address liable) = rollup.batchDataStore(1); + assertEq(liable, address(0)); + assertEq(rollup.pendingBatchCount(address(0xBEEF)), 0); + bytes32 sequencerSetVerifyHash; + assembly { + sequencerSetVerifyHash := mload(add(add(header1, 0x20), 185)) + } + assertEq(sequencerSetVerifyHash, bytes32(0)); + assertEq(rollup.committedBatches(1), keccak256(header1)); + } + + function test_liabilityUnderflowFailsClosed() public { + bytes memory header0 = _importGenesis(); + bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); + bytes32 countSlot = keccak256(abi.encode(alice, PENDING_BATCH_COUNT_SLOT)); + hevm.store(address(rollup), countSlot, bytes32(0)); + + hevm.prank(multisig); + hevm.expectRevert("pending batch count underflow"); + rollup.revertBatch(header1, 1); + assertEq(rollup.lastCommittedBatchIndex(), 1); + } + + function test_initialize2And3AreOwnerOnly() public { + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + rollup.initialize2(ROOT_1); + hevm.prank(multisig); + rollup.initialize2(ROOT_1); + + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + rollup.initialize3(3600); + hevm.prank(multisig); + rollup.initialize3(3600); + } + + function test_initialize4ValidatesInterfaceAndClearsLegacyTailOwnerField() public { + _importGenesis(); + bytes32 batchDataBase = keccak256(abi.encode(uint256(0), BATCH_DATA_STORE_SLOT)); + hevm.store(address(rollup), bytes32(uint256(batchDataBase) + 3), bytes32(uint256(uint160(alice)))); + (uint256 originBefore, uint256 finalizeBefore, uint256 blockBefore, address legacyTail) = rollup + .batchDataStore(0); + assertEq(legacyTail, alice); + + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + rollup.initialize4(address(submitter)); + + hevm.prank(multisig); + hevm.expectRevert("invalid submitter"); + rollup.initialize4(address(0x1234)); + + SubmitterCandidateMock malformed = new SubmitterCandidateMock(address(rollup), CHALLENGE_DEPOSIT, 0); + malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.Short); + hevm.prank(multisig); + hevm.expectRevert("invalid submitter interface"); + rollup.initialize4(address(malformed)); + malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.Long); + hevm.prank(multisig); + hevm.expectRevert("invalid submitter interface"); + rollup.initialize4(address(malformed)); + malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.BadAddressEncoding); + hevm.prank(multisig); + hevm.expectRevert("invalid rollup encoding"); + rollup.initialize4(address(malformed)); + + SubmitterCandidateMock mismatch = new SubmitterCandidateMock(address(1), CHALLENGE_DEPOSIT, 0); + hevm.prank(multisig); + hevm.expectRevert("submitter rollup mismatch"); + rollup.initialize4(address(mismatch)); + SubmitterCandidateMock badActive = new SubmitterCandidateMock(address(rollup), CHALLENGE_DEPOSIT, 1); + hevm.prank(multisig); + hevm.expectRevert("invalid submitter state"); + rollup.initialize4(address(badActive)); + SubmitterCandidateMock zeroDeposit = new SubmitterCandidateMock(address(rollup), 0, 0); + hevm.prank(multisig); + hevm.expectRevert("invalid submitter state"); + rollup.initialize4(address(zeroDeposit)); + + hevm.prank(multisig); + rollup.initialize4(address(submitter)); + assertEq(rollup.submitterContract(), address(submitter)); + (uint256 originAfter, uint256 finalizeAfter, uint256 blockAfter, address tailSubmitter) = rollup.batchDataStore( + 0 + ); + assertEq(originAfter, originBefore); + assertEq(finalizeAfter, finalizeBefore); + assertEq(blockAfter, blockBefore); + assertEq(tailSubmitter, address(0)); + + hevm.prank(multisig); + hevm.expectRevert("Initializable: contract is already initialized"); + rollup.initialize4(address(submitter)); + } + + function test_initialize4PendingBatchRevertsWithoutConsumingVersion() public { + bytes memory header0 = _importGenesis(); + bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); + + hevm.prank(multisig); + hevm.expectRevert("pending batches"); + rollup.initialize4(address(submitter)); + + hevm.prank(multisig); + rollup.revertBatch(header1, 1); + hevm.prank(multisig); + rollup.initialize4(address(submitter)); + } + + function _importGenesis() internal returns (bytes memory header0) { + header0 = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); + assembly { + mstore(add(header0, add(0x20, 25)), 1) + mstore(add(header0, add(0x20, 57)), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) + mstore(add(header0, add(0x20, 121)), 1) + } + hevm.prank(multisig); + rollup.importGenesisBatch(header0); + } + + function _commitStateAs( + address actor, + bytes memory parentHeader, + uint256 batchIndex, + bytes32 previousRoot, + bytes32 postRoot + ) internal returns (bytes memory header) { + _setStoredBlobHash(batchIndex); + hevm.mockCall( + address(l1MessageQueueWithGasPriceOracle), + abi.encodeWithSignature("getFirstUnfinalizedMessageEnqueueTime()"), + abi.encode(block.timestamp) + ); + bytes32 withdrawalRoot = bytes32(batchIndex + 100); + IRollup.BatchDataInput memory input = IRollup.BatchDataInput( + 0, + parentHeader, + uint64(batchIndex), + 0, + previousRoot, + postRoot, + withdrawalRoot + ); + hevm.prank(actor); + rollup.commitState(input); + + header = _buildStateHeader(batchIndex, previousRoot, postRoot, withdrawalRoot); + assertEq(rollup.committedBatches(batchIndex), keccak256(header)); + } + + function _buildStateHeader( + uint256 batchIndex, + bytes32 previousRoot, + bytes32 postRoot, + bytes32 withdrawalRoot + ) internal view returns (bytes memory header) { + header = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); + bytes32 dataHash = _computeDataHash(uint64(batchIndex), 0); + bytes32 parentHash = rollup.committedBatches(batchIndex - 1); + assembly { + let p := add(header, 0x20) + mstore(p, 0) + mstore(add(p, 1), shl(192, batchIndex)) + mstore(add(p, 25), dataHash) + mstore(add(p, 57), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) + mstore(add(p, 89), previousRoot) + mstore(add(p, 121), postRoot) + mstore(add(p, 153), withdrawalRoot) + mstore(add(p, 185), 0) + mstore(add(p, 217), parentHash) + } + } +} + /// @dev Tests for Rollup V2 multi-blob batch header support (simplified: 257-byte header with aggregated blob hash). contract RollupCommitBatchV2Test is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); - IRollup.BatchSignatureInput public batchSignatureInput; bytes public batchHeader0; bytes32 public batchHash0; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - // Register staker - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory addrs = new address[](1); - addrs[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(addrs, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + _registerAndStakeSubmitter(alice); // Import genesis batch (V0) bytes memory _genesis = new bytes(249); @@ -1557,7 +1726,7 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { Rollup Integration Tests //////////////////////////////////////////////////////////////*/ - /// @dev commitBatch with V2 requires at least 1 blob (reverts in test env where blobhash(0)=0). + /// @dev commitBatch with must carry blob (reverts in test env where blobhash(0)=0). function test_commitBatchV2_reverts_without_blob() public { IRollup.BatchDataInput memory batchDataInput = IRollup.BatchDataInput({ version: 2, @@ -1570,8 +1739,8 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { }); hevm.prank(alice); - hevm.expectRevert("V2 requires at least 1 blob"); - rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.expectRevert("must carry blob"); + rollup.commitBatch(batchDataInput); } /// @dev V2 _loadBatchHeader accepts a valid 257-byte V2 header (uses V1 loader). diff --git a/contracts/contracts/test/Submitter.t.sol b/contracts/contracts/test/Submitter.t.sol new file mode 100644 index 000000000..c8637f63b --- /dev/null +++ b/contracts/contracts/test/Submitter.t.sol @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import "forge-std/Test.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; +import {Submitter} from "../l1/rollup/Submitter.sol"; + +contract LiabilityRollupMock { + enum ReturnMode { + Normal, + RevertCall, + Short, + Long, + BurnGas + } + + mapping(address submitter => uint256 count) public counts; + ReturnMode public returnMode; + + function setPendingBatchCount(address submitter, uint256 count) external { + counts[submitter] = count; + } + + function setReturnMode(ReturnMode mode) external { + returnMode = mode; + } + + function slash(ISubmitter submitterContract, address submitter) external returns (uint256) { + return submitterContract.slash(submitter); + } + + receive() external payable {} + + fallback() external payable { + require(msg.sig == bytes4(keccak256("pendingBatchCount(address)")), "unknown selector"); + ReturnMode mode = returnMode; + address submitter; + assembly { + submitter := calldataload(4) + } + uint256 count = counts[submitter]; + if (mode == ReturnMode.RevertCall) revert("getter reverted"); + if (mode == ReturnMode.BurnGas) { + assembly { + for {} 1 {} {} + } + } + assembly { + mstore(0, count) + } + if (mode == ReturnMode.Short) { + assembly { + return(0, 31) + } + } + if (mode == ReturnMode.Long) { + assembly { + mstore(32, 1) + return(0, 64) + } + } + assembly { + return(0, 32) + } + } +} + +contract RejectEther { + function stakeInto(Submitter target) external { + target.stake{value: address(this).balance}(); + } + + function claimFrom(Submitter target, address receiver) external { + target.claimCredit(receiver); + } + + receive() external payable { + revert("reject ether"); + } +} + +contract BurnRefundGas { + receive() external payable { + assembly { + for {} 1 {} {} + } + } +} + +contract ReentrantSubmitterActor { + Submitter internal immutable target; + bool public reentrySucceeded; + bytes32 public reentryErrorHash; + + constructor(Submitter target_) { + target = target_; + } + + function stakeInto() external { + target.stake{value: address(this).balance}(); + } + + function withdrawToSelf() external { + target.withdraw(address(this)); + } + + receive() external payable { + try target.claimWithdrawal(address(this)) { + reentrySucceeded = true; + } catch (bytes memory reason) { + reentryErrorHash = keccak256(reason); + } + } +} + +contract SubmitterTest is Test { + uint256 internal constant MINIMUM_STAKE = 1 ether; + uint256 internal constant CHALLENGE_DEPOSIT = 2 ether; + uint256 internal constant REWARD_PERCENTAGE = 25; + + address internal owner = address(0xA11CE); + address internal proxyAdmin = address(0xA11); + address internal alice = address(0xB0B); + address internal bob = address(0xCAFE); + + LiabilityRollupMock internal rollupMock; + Submitter internal implementation; + Submitter internal submitter; + + function setUp() public { + vm.deal(alice, 100 ether); + vm.deal(bob, 100 ether); + rollupMock = new LiabilityRollupMock(); + implementation = new Submitter(); + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(implementation), + proxyAdmin, + abi.encodeCall( + Submitter.initialize, (owner, address(rollupMock), MINIMUM_STAKE, CHALLENGE_DEPOSIT, REWARD_PERCENTAGE) + ) + ); + submitter = Submitter(payable(address(proxy))); + } + + function test_initialize_proxyAndImplementationProtection() public { + assertEq(submitter.owner(), owner); + assertEq(submitter.rollupContract(), address(rollupMock)); + assertEq(submitter.minimumStake(), MINIMUM_STAKE); + assertEq(submitter.challengeDeposit(), CHALLENGE_DEPOSIT); + assertEq(submitter.rewardPercentage(), REWARD_PERCENTAGE); + + vm.expectRevert("Initializable: contract is already initialized"); + implementation.initialize(owner, address(rollupMock), 1, 1, 1); + + vm.prank(owner); + vm.expectRevert("Initializable: contract is already initialized"); + submitter.initialize(owner, address(rollupMock), 1, 1, 1); + } + + function test_initialize_rejectsInvalidParameters() public { + _expectProxyInitializationRevert(address(0), address(rollupMock), 1, 1, 1, "invalid owner"); + _expectProxyInitializationRevert(owner, address(0), 1, 1, 1, "invalid rollup contract"); + _expectProxyInitializationRevert(owner, alice, 1, 1, 1, "invalid rollup contract"); + _expectProxyInitializationRevert(owner, address(rollupMock), 0, 1, 1, "invalid minimum stake"); + _expectProxyInitializationRevert(owner, address(rollupMock), 1, 0, 1, "invalid challenge deposit"); + _expectProxyInitializationRevert(owner, address(rollupMock), 1, 1, 0, "invalid reward percentage"); + _expectProxyInitializationRevert(owner, address(rollupMock), 1, 1, 101, "invalid reward percentage"); + } + + function test_addStakeAndDynamicMinimum() public { + vm.prank(alice); + vm.expectRevert("Ownable: caller is not the owner"); + submitter.addSubmitter(alice); + + vm.prank(owner); + submitter.addSubmitter(alice); + assertFalse(submitter.isActive(alice)); + + vm.prank(alice); + vm.expectRevert("below minimum stake"); + submitter.stake{value: MINIMUM_STAKE - 1}(); + + vm.prank(alice); + submitter.stake{value: MINIMUM_STAKE}(); + assertTrue(submitter.isActive(alice)); + + vm.prank(owner); + submitter.setMinimumStake(2 ether); + assertFalse(submitter.isActive(alice)); + + vm.prank(alice); + vm.expectRevert("below minimum stake"); + submitter.stake{value: 0.5 ether}(); + vm.prank(alice); + submitter.stake{value: 1 ether}(); + assertTrue(submitter.isActive(alice)); + + vm.prank(owner); + submitter.setMinimumStake(3 ether); + assertFalse(submitter.isActive(alice)); + vm.prank(owner); + submitter.setMinimumStake(2 ether); + assertTrue(submitter.isActive(alice)); + } + + function test_multipleSubmittersCanBeActive() public { + _registerAndStake(alice, MINIMUM_STAKE); + _registerAndStake(bob, MINIMUM_STAKE + 1); + assertTrue(submitter.isActive(alice)); + assertTrue(submitter.isActive(bob)); + } + + function test_withdraw_noLiabilityPaysAndRequiresFreshRegistration() public { + _registerAndStake(alice, MINIMUM_STAKE); + uint256 before = bob.balance; + + vm.prank(alice); + submitter.withdraw(bob); + + assertEq(bob.balance - before, MINIMUM_STAKE); + assertEq(submitter.stakeOf(alice), 0); + assertFalse(submitter.exiting(alice)); + assertFalse(submitter.registered(alice)); + vm.prank(alice); + vm.expectRevert("not stakeable"); + submitter.stake{value: MINIMUM_STAKE}(); + } + + function test_remove_pendingExitRejectsDuplicateAddUntilClaimed() public { + vm.prank(owner); + submitter.addSubmitter(alice); + vm.prank(owner); + vm.expectRevert("invalid submitter"); + submitter.addSubmitter(alice); + + vm.prank(alice); + submitter.stake{value: MINIMUM_STAKE}(); + rollupMock.setPendingBatchCount(alice, 1); + vm.prank(owner); + submitter.removeSubmitter(alice); + + assertFalse(submitter.registered(alice)); + assertTrue(submitter.exiting(alice)); + assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + vm.prank(owner); + vm.expectRevert("invalid submitter"); + submitter.addSubmitter(alice); + vm.prank(alice); + vm.expectRevert("pending batch liability"); + submitter.claimWithdrawal(alice); + + rollupMock.setPendingBatchCount(alice, 0); + vm.prank(alice); + submitter.claimWithdrawal(alice); + vm.prank(owner); + submitter.addSubmitter(alice); + assertTrue(submitter.registered(alice)); + } + + function test_exit_keepsStakeSlashable_untilAllBatchesTerminate() public { + _registerAndStake(alice, MINIMUM_STAKE); + rollupMock.setPendingBatchCount(alice, 2); + + vm.prank(alice); + submitter.withdraw(alice); + assertFalse(submitter.isActive(alice)); + assertTrue(submitter.exiting(alice)); + assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + + uint256 reward = rollupMock.slash(submitter, alice); + assertEq(reward, MINIMUM_STAKE / 4); + assertEq(submitter.stakeOf(alice), 0); + assertTrue(submitter.exiting(alice)); + assertFalse(submitter.registered(alice)); + + rollupMock.setPendingBatchCount(alice, 0); + vm.prank(alice); + submitter.claimWithdrawal(alice); + assertFalse(submitter.exiting(alice)); + vm.prank(alice); + vm.expectRevert("not stakeable"); + submitter.stake{value: MINIMUM_STAKE}(); + + vm.prank(owner); + submitter.addSubmitter(alice); + vm.prank(alice); + submitter.stake{value: MINIMUM_STAKE}(); + assertTrue(submitter.isActive(alice)); + } + + function test_withdraw_getterFailuresFailClosed() public { + LiabilityRollupMock.ReturnMode[4] memory modes = [ + LiabilityRollupMock.ReturnMode.RevertCall, + LiabilityRollupMock.ReturnMode.Short, + LiabilityRollupMock.ReturnMode.Long, + LiabilityRollupMock.ReturnMode.BurnGas + ]; + for (uint256 i; i < modes.length; ++i) { + address actor = address(uint160(0x1000 + i)); + vm.deal(actor, 10 ether); + _registerAndStake(actor, MINIMUM_STAKE); + rollupMock.setReturnMode(modes[i]); + vm.prank(actor); + submitter.withdraw(actor); + assertFalse(submitter.isActive(actor)); + assertTrue(submitter.exiting(actor)); + assertEq(submitter.stakeOf(actor), MINIMUM_STAKE); + rollupMock.setReturnMode(LiabilityRollupMock.ReturnMode.Normal); + vm.prank(actor); + submitter.claimWithdrawal(actor); + } + } + + function test_receiverFailureCreditsWithoutBlockingRemove() public { + RejectEther actor = new RejectEther(); + vm.deal(address(actor), MINIMUM_STAKE); + vm.prank(owner); + submitter.addSubmitter(address(actor)); + actor.stakeInto(submitter); + + vm.prank(owner); + submitter.removeSubmitter(address(actor)); + assertFalse(submitter.registered(address(actor))); + assertFalse(submitter.exiting(address(actor))); + assertEq(submitter.claimable(address(actor)), MINIMUM_STAKE); + + uint256 before = bob.balance; + actor.claimFrom(submitter, bob); + assertEq(bob.balance - before, MINIMUM_STAKE); + assertEq(submitter.claimable(address(actor)), 0); + } + + function test_withdraw_revertingAndGasBurningReceiversBecomeCredit() public { + RejectEther reject = new RejectEther(); + BurnRefundGas burner = new BurnRefundGas(); + + _registerAndStake(alice, MINIMUM_STAKE); + vm.prank(alice); + submitter.withdraw(address(reject)); + assertEq(submitter.claimable(alice), MINIMUM_STAKE); + + _registerAndStake(bob, MINIMUM_STAKE); + vm.prank(bob); + submitter.withdraw(address(burner)); + assertEq(submitter.claimable(bob), MINIMUM_STAKE); + } + + function test_withdraw_receiverReentryIsBlocked() public { + ReentrantSubmitterActor actor = new ReentrantSubmitterActor(submitter); + vm.deal(address(actor), MINIMUM_STAKE); + vm.prank(owner); + submitter.addSubmitter(address(actor)); + actor.stakeInto(); + + actor.withdrawToSelf(); + + assertFalse(actor.reentrySucceeded()); + assertEq( + actor.reentryErrorHash(), + keccak256(abi.encodeWithSignature("Error(string)", "ReentrancyGuard: reentrant call")) + ); + assertEq(address(actor).balance, MINIMUM_STAKE); + assertEq(submitter.stakeOf(address(actor)), 0); + } + + function test_claimCreditFailureRollsBackCredit() public { + RejectEther reject = new RejectEther(); + _registerAndStake(alice, MINIMUM_STAKE); + vm.prank(alice); + submitter.withdraw(address(reject)); + + vm.prank(alice); + vm.expectRevert("ETH transfer failed"); + submitter.claimCredit(address(reject)); + assertEq(submitter.claimable(alice), MINIMUM_STAKE); + } + + function test_slashPermissionsZeroAndOwnerAccounting() public { + _registerAndStake(alice, 4 ether); + + vm.prank(owner); + vm.expectRevert("only rollup contract"); + submitter.slash(alice); + assertEq(rollupMock.slash(submitter, address(0)), 0); + + uint256 rollupBefore = address(rollupMock).balance; + assertEq(rollupMock.slash(submitter, alice), 1 ether); + assertEq(address(rollupMock).balance - rollupBefore, 1 ether); + assertEq(submitter.slashRemaining(), 3 ether); + assertEq(address(submitter).balance, 3 ether); + + uint256 ownerBefore = owner.balance; + vm.prank(owner); + submitter.claimSlashRemaining(owner); + assertEq(owner.balance - ownerBefore, 3 ether); + assertEq(submitter.slashRemaining(), 0); + } + + function test_parameterUpdatesValidateBoundsAndPermissions() public { + vm.prank(alice); + vm.expectRevert("Ownable: caller is not the owner"); + submitter.updateChallengeDeposit(3 ether); + + vm.startPrank(owner); + vm.expectRevert("invalid minimum stake"); + submitter.setMinimumStake(0); + vm.expectRevert("invalid challenge deposit"); + submitter.updateChallengeDeposit(CHALLENGE_DEPOSIT); + vm.expectRevert("invalid reward percentage"); + submitter.updateRewardPercentage(101); + submitter.updateChallengeDeposit(3 ether); + submitter.updateRewardPercentage(50); + vm.stopPrank(); + + assertEq(submitter.challengeDeposit(), 3 ether); + assertEq(submitter.rewardPercentage(), 50); + } + + function testFuzz_accountingConservation(uint96 aliceStake, uint96 bobStake) public { + aliceStake = uint96(bound(aliceStake, MINIMUM_STAKE, 20 ether)); + bobStake = uint96(bound(bobStake, MINIMUM_STAKE, 20 ether)); + _registerAndStake(alice, aliceStake); + _registerAndStake(bob, bobStake); + + RejectEther reject = new RejectEther(); + vm.prank(alice); + submitter.withdraw(address(reject)); + rollupMock.slash(submitter, bob); + + uint256 tracked = submitter.stakeOf(alice) + submitter.stakeOf(bob); + tracked += submitter.claimable(alice) + submitter.claimable(bob); + tracked += submitter.slashRemaining(); + assertLe(tracked, address(submitter).balance); + } + + function _registerAndStake(address actor, uint256 amount) internal { + vm.prank(owner); + submitter.addSubmitter(actor); + vm.prank(actor); + submitter.stake{value: amount}(); + } + + function _expectProxyInitializationRevert( + address owner_, + address rollup_, + uint256 minimumStake_, + uint256 deposit_, + uint256 percentage_, + string memory reason + ) internal { + Submitter freshImplementation = new Submitter(); + vm.expectRevert(bytes(reason)); + new TransparentUpgradeableProxy( + address(freshImplementation), + proxyAdmin, + abi.encodeCall(Submitter.initialize, (owner_, rollup_, minimumStake_, deposit_, percentage_)) + ); + } +} diff --git a/contracts/contracts/test/base/L1MessageBase.t.sol b/contracts/contracts/test/base/L1MessageBase.t.sol index d2fa9db4e..0cd82ba51 100644 --- a/contracts/contracts/test/base/L1MessageBase.t.sol +++ b/contracts/contracts/test/base/L1MessageBase.t.sol @@ -7,23 +7,20 @@ import {CommonTest} from "./CommonTest.t.sol"; import {Whitelist} from "../../libraries/common/Whitelist.sol"; import {L1CrossDomainMessenger} from "../../l1/L1CrossDomainMessenger.sol"; import {L1MessageQueueWithGasPriceOracle} from "../../l1/rollup/L1MessageQueueWithGasPriceOracle.sol"; -import {L1Staking} from "../../l1/staking/L1Staking.sol"; +import {Submitter} from "../../l1/rollup/Submitter.sol"; import {Rollup} from "../../l1/rollup/Rollup.sol"; import {IRollup} from "../../l1/rollup/IRollup.sol"; import {BatchHeaderCodecV0} from "../../libraries/codec/BatchHeaderCodecV0.sol"; import {MockZkEvmVerifier} from "../../mock/MockZkEvmVerifier.sol"; contract L1MessageBaseTest is CommonTest { - // Staking config - L1Staking public l1Staking; - L1Staking public l1StakingImpl; + // Submitter config + Submitter public submitter; + Submitter public submitterImpl; uint256 public constant STAKING_VALUE = 1e18; // 1 eth uint256 public constant CHALLENGE_DEPOSIT = 1e18; // 1 eth - uint256 public constant LOCK_BLOCKS = 3; uint256 public rewardPercentage = 20; - uint32 public defaultGasLimitAdd = 1000000; - uint32 public defaultGasLimitRemove = 10000000; // Rollup config Rollup public rollup; @@ -92,6 +89,14 @@ contract L1MessageBaseTest is CommonTest { ); } + function _registerAndStakeSubmitter(address account) internal { + hevm.deal(account, 5 * STAKING_VALUE); + hevm.prank(multisig); + submitter.addSubmitter(account); + hevm.prank(account); + submitter.stake{value: STAKING_VALUE}(); + } + /// @dev Build V0 batch header for commitBatchWithProof (blob = ZERO_VERSIONED_HASH). function _createBatchHeaderV0ForProof( uint256 batchIndex, @@ -144,7 +149,7 @@ contract L1MessageBaseTest is CommonTest { address(multisig), new bytes(0) ); - TransparentUpgradeableProxy l1StakingProxy = new TransparentUpgradeableProxy( + TransparentUpgradeableProxy submitterProxy = new TransparentUpgradeableProxy( address(emptyContract), address(multisig), new bytes(0) @@ -158,7 +163,7 @@ contract L1MessageBaseTest is CommonTest { address(alice) ); l1CrossDomainMessengerImpl = new L1CrossDomainMessenger(); - l1StakingImpl = new L1Staking(payable(l1CrossDomainMessengerProxy)); + submitterImpl = new Submitter(); // upgrade and initialize ITransparentUpgradeableProxy(address(rollupProxy)).upgradeToAndCall( @@ -166,7 +171,7 @@ contract L1MessageBaseTest is CommonTest { abi.encodeCall( Rollup.initialize, ( - address(l1StakingProxy), + address(submitterProxy), address(l1MessageQueueWithGasPriceOracleProxy), // _messageQueue address(verifier), // _verifier finalizationPeriodSeconds, // _finalizationPeriodSeconds @@ -196,18 +201,16 @@ contract L1MessageBaseTest is CommonTest { ) ) ); - ITransparentUpgradeableProxy(address(l1StakingProxy)).upgradeToAndCall( - address(l1StakingImpl), + ITransparentUpgradeableProxy(address(submitterProxy)).upgradeToAndCall( + address(submitterImpl), abi.encodeCall( - L1Staking.initialize, + Submitter.initialize, ( + multisig, address(rollupProxy), STAKING_VALUE, CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove + rewardPercentage ) ) ); @@ -217,9 +220,9 @@ contract L1MessageBaseTest is CommonTest { l1MessageQueueWithGasPriceOracle = L1MessageQueueWithGasPriceOracle( address(l1MessageQueueWithGasPriceOracleProxy) ); - l1Staking = L1Staking(address(l1StakingProxy)); + submitter = Submitter(payable(address(submitterProxy))); - _changeAdmin(address(l1Staking)); + _changeAdmin(address(submitter)); _changeAdmin(address(rollup)); _changeAdmin(address(l1CrossDomainMessenger)); _changeAdmin(address(l1MessageQueueWithGasPriceOracle)); From e159e51630e3fb108d7f2685ce126d0ef65232a9 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:31:37 +0800 Subject: [PATCH 03/38] feat(deploy): install submitter and retire legacy staking --- bindings/Makefile | 11 +- bindings/bin/l1staking_deployed.hex | 1 - bindings/bin/rollup_deployed.hex | 2 +- bindings/bin/submitter_deployed.hex | 1 + bindings/bindings/l1staking.go | 3445 ----------------- bindings/bindings/l1staking_more.go | 25 - bindings/bindings/rollup.go | 408 +- bindings/bindings/rollup_more.go | 4 +- bindings/bindings/submitter.go | 2863 ++++++++++++++ bindings/bindings/submitter_more.go | 25 + contracts/deploy/013-DeployProxys.ts | 10 +- contracts/deploy/014-DeployImpls.ts | 43 +- contracts/deploy/015-SubmitterInstall.ts | 109 + contracts/deploy/016-RollupInit.ts | 10 +- contracts/deploy/018-StakingInit.ts | 128 - contracts/deploy/019-AdminTransfer.ts | 10 +- contracts/deploy/020-ContractInit.ts | 44 +- contracts/deploy/021-StakingRegister.ts | 57 - contracts/deploy/021-SubmitterRegister.ts | 38 + contracts/deploy/index.ts | 10 +- contracts/hardhat.config.ts | 8 +- .../retire-l1-staking.spec.ts | 122 + .../integration-test/submitter-deploy.spec.ts | 72 + .../legacy-l1-staking-retirement.example.json | 18 + contracts/scripts/retire-l1-staking.ts | 664 ++++ contracts/src/deploy-config/holesky.ts | 16 +- contracts/src/deploy-config/hoodi.ts | 16 +- contracts/src/deploy-config/l1.ts | 16 +- contracts/src/deploy-config/qanetl1.ts | 16 +- contracts/src/deploy-config/sepolia.ts | 8 +- contracts/src/deploy-config/testnetl1.ts | 8 +- contracts/src/deploy-utils.ts | 5 +- contracts/src/types.ts | 15 +- contracts/tasks/deploy.ts | 54 +- contracts/tasks/staking_upgrade.ts | 901 ----- 35 files changed, 4327 insertions(+), 4856 deletions(-) delete mode 100644 bindings/bin/l1staking_deployed.hex create mode 100644 bindings/bin/submitter_deployed.hex delete mode 100644 bindings/bindings/l1staking.go delete mode 100644 bindings/bindings/l1staking_more.go create mode 100644 bindings/bindings/submitter.go create mode 100644 bindings/bindings/submitter_more.go create mode 100644 contracts/deploy/015-SubmitterInstall.ts delete mode 100644 contracts/deploy/018-StakingInit.ts delete mode 100644 contracts/deploy/021-StakingRegister.ts create mode 100644 contracts/deploy/021-SubmitterRegister.ts create mode 100644 contracts/integration-test/retire-l1-staking.spec.ts create mode 100644 contracts/integration-test/submitter-deploy.spec.ts create mode 100644 contracts/ops/legacy-l1-staking-retirement.example.json create mode 100644 contracts/scripts/retire-l1-staking.ts delete mode 100644 contracts/tasks/staking_upgrade.ts diff --git a/bindings/Makefile b/bindings/Makefile index a98e10d37..616ebf372 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -5,7 +5,7 @@ pkg := bindings all: version mkdir bindings more bindings: \ - l1-staking-bindings \ + submitter-bindings \ l1-cross-domain-messenger-bindings \ l1-standard-erc20-gateway-bindings \ l1-eth-gateway-bindings \ @@ -65,9 +65,9 @@ compile-forge: ./compile.sh forge ## L1 -# Staking -l1-staking-bindings: compile - ./gen_bindings.sh contracts/l1/staking/L1Staking.sol:L1Staking $(pkg) +# Submitter +submitter-bindings: compile + ./gen_bindings.sh contracts/l1/rollup/Submitter.sol:Submitter $(pkg) # CrossDomainMessenger l1-cross-domain-messenger-bindings: compile @@ -194,7 +194,7 @@ more: compile-forge go run ./gen/main.go \ -artifacts ../contracts/artifacts \ -out ./bindings \ - -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,L1Staking,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ + -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,Submitter,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ -package bindings mkdir: @@ -211,4 +211,3 @@ test: lint: GOBIN=$(PWD)/build/bin go run ../build/lint.go .PHONY: lint - diff --git a/bindings/bin/l1staking_deployed.hex b/bindings/bin/l1staking_deployed.hex deleted file mode 100644 index 401476f33..000000000 --- a/bindings/bin/l1staking_deployed.hex +++ /dev/null @@ -1 +0,0 @@ -0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bin/rollup_deployed.hex b/bindings/bin/rollup_deployed.hex index 68a52ca9c..502f165cb 100644 --- a/bindings/bin/rollup_deployed.hex +++ b/bindings/bin/rollup_deployed.hex @@ -1 +1 @@ -0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a +0x608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610b2c578063f2fde38b14610b4b578063f8fa010f14610b6a578063fb1e8b0414610b89575f80fd5b8063d279c19114610ac4578063d8dc99d214610ae3578063de8b303514610af8578063dff7827e14610b17575f80fd5b8063c5553892116100d8578063c555389214610a5e578063cd4edc6914610a7d578063ce5db8d614610a90578063cf9a674514610aa5575f80fd5b8063b3e0a50914610a01578063b8d0a1b014610a20578063bedb86fb14610a3f575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d14610983578063b31a77d3146109ae578063b3484425146109c3578063b35dac4e146109e2575f80fd5b8063a415d8dc14610921578063a479265d1461094f578063a4f209b014610964575f80fd5b80638f1d3776116101a35780638f1d377614610802578063910129d4146108b257806397fc007c146108e3578063a3c9e94c14610902575f80fd5b806388b1ea09146107a15780638da5cb5b146107ba5780638ef622a8146107d7575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107245780636c578c1d1461074f578063715018a61461076e578063728cdbca14610782575f80fd5b80635f77cf1d1461069a57806361267290146106e657806367caa37a14610705575f80fd5b806341f756da1161027957806341f756da146105df57806357e0af6c146105f25780635c975abb146106115780635ef7a94a14610628575f80fd5b80632b7ac3f3146105745780633b70c18a146105ab5780633e001b66146105ca575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e36600461529d565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046152ca565b610b9e565b005b348015610406575f80fd5b506103f9610415366004615328565b610c70565b348015610425575f80fd5b506103a261043436600461529d565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004615370565b610fb5565b34801561047b575f80fd5b506103f961048a3660046153bf565b6114db565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be36600461529d565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee36600461529d565b61189a565b3480156104fe575f80fd5b506103cc61050d36600461529d565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc61053836600461529d565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc61056336600461529d565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c54610593906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105b6575f80fd5b50609b54610593906001600160a01b031681565b3480156105d5575f80fd5b506103cc60aa5481565b6103f96105ed36600461544d565b6118c8565b3480156105fd575f80fd5b506103f961060c36600461529d565b611b66565b34801561061c575f80fd5b5060655460ff166103a2565b348015610633575f80fd5b5061067161064236600461529d565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106a5575f80fd5b506106cd7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b3480156106f1575f80fd5b506103f961070036600461529d565b611c11565b348015610710575f80fd5b506103f961071f36600461544d565b611dee565b34801561072f575f80fd5b506103cc61073e36600461529d565b60ab6020525f908152604090205481565b34801561075a575f80fd5b506103f96107693660046152ca565b612139565b348015610779575f80fd5b506103f96121f6565b34801561078d575f80fd5b506103f961079c366004615487565b612209565b3480156107ac575f80fd5b5060a6546103a29060ff1681565b3480156107c5575f80fd5b506033546001600160a01b0316610593565b3480156107e2575f80fd5b506103cc6107f13660046152ca565b60ae6020525f908152604090205481565b34801561080d575f80fd5b5061086e61081c36600461529d565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108bd575f80fd5b506103a26108cc36600461529d565b5f90815260a4602052604090206003015460ff1690565b3480156108ee575f80fd5b506103f96108fd3660046152ca565b612512565b34801561090d575f80fd5b50609754610593906001600160a01b031681565b34801561092c575f80fd5b506103a261093b3660046152ca565b609f6020525f908152604090205460ff1681565b34801561095a575f80fd5b506103cc60995481565b34801561096f575f80fd5b506103f961097e36600461529d565b6125f5565b34801561098e575f80fd5b506103cc61099d3660046152ca565b60a56020525f908152604090205481565b3480156109b9575f80fd5b506103cc60a85481565b3480156109ce575f80fd5b506103f96109dd3660046154e2565b6126a5565b3480156109ed575f80fd5b506103f96109fc3660046152ca565b6129b2565b348015610a0c575f80fd5b506103f9610a1b366004615370565b612a0b565b348015610a2b575f80fd5b506103f9610a3a3660046154e2565b612d9c565b348015610a4a575f80fd5b506103f9610a59366004615556565b612e25565b348015610a69575f80fd5b506103f9610a7836600461529d565b612f63565b6103f9610a8b366004615588565b613006565b348015610a9b575f80fd5b506103cc60985481565b348015610ab0575f80fd5b506103f9610abf36600461529d565b613598565b348015610acf575f80fd5b506103f9610ade3660046152ca565b61370f565b348015610aee575f80fd5b506103cc60ac5481565b348015610b03575f80fd5b506103a2610b1236600461529d565b6137ce565b348015610b22575f80fd5b506103cc609a5481565b348015610b37575f80fd5b506103f9610b4636600461529d565b613818565b348015610b56575f80fd5b506103f9610b653660046152ca565b6138bb565b348015610b75575f80fd5b506103f9610b843660046152ca565b613948565b348015610b94575f80fd5b506103cc60a95481565b610ba6613e4d565b6001600160a01b0381165f908152609f602052604090205460ff1615610c135760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c78613e4d565b5f8111610cc75760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c0a565b5f80610cd38585613ea7565b915091505f610ce6836001015160c01c90565b5f81815260a160205260409020549091508214610d455760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f60a181610d5387856155dd565b81526020019081526020015f205414610dd35760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b609d548111610e4a5760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b610e556001826155f0565b609e555b8315610fad57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610e9381613f4f565b5f81815260a16020526040812055610eaa816137ce565b15610f05575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ef59084906155dd565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f65575060a85481145b15610f6f575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e59575b505050505050565b60a854156110055760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b61100d614002565b5f806110198484613ea7565b915091505f61102c836001015160c01c90565b5f81815260a16020526040902054909150821461108b5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6110948161189a565b6110e05760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b6110e9816137ce565b156111365760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a4602052604090206003015460ff16156111975760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c0a565b5f81815260a260205260409020600101544210156111f75760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c0a565b605983015160a05f61120a6001856155f0565b81526020019081526020015f2054146112655760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f81815260a06020526040902054156112c05760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c0a565b80609d54600101146113145760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b609d819055600160a35f611329866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561137861136b846011015160c01c90565b600985015160c01c614055565b61138181613f4f565b60a25f61138f6001846155f0565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113eb90846155f0565b81526020019081526020015f205f905560ad5f60018361140b91906155f0565b81526020019081526020015f205f905560a45f60018361142b91906155f0565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d6114b7866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a8541561152b5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611533614002565b60ac54609e545f90815260a260205260408120549091429161155591906155dd565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d19190615603565b6115db91906155dd565b109050811580156115e95750805b15611650575f6115ff6080890160608a0161561a565b61ffff16116116505760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b81806116595750805b6116a55760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c0a565b5f6116bb6116b660208a018a61563b565b613ea7565b5090505f6116cd826001015160c01c90565b6116d89060016155dd565b5f81815260ad60205260408120549192509015611778575f49156117645760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c0a565b505f81815260ad6020526040902054611793565b61179061178860208c018c61569c565b60ff16614112565b90505b61179e8a5f8361424d565b5f806117aa8b8b613ea7565b915091505f6117bd836001015160c01c90565b905080609e54146118105760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461186c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f81815260a2602052604090204260019091015561188b838b8b6147af565b50505050505050505050505050565b5f81815260a26020526040812054158015906118c257505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611934573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195891906156bc565b6119a45760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a854156119f45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6119fc614002565b5f49611a4a5760405162461bcd60e51b815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aae573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad29190615603565b611adc91906155dd565b1015611b44575f611af3608083016060840161561a565b61ffff1611611b445760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b5f611b55611788602084018461569c565b9050611b6282338361424d565b5050565b611b6e613e4d565b5f81118015611b7f57506099548114155b611bcb5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c0a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c3157505f5460ff8083169116105b611ca35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055611cbe613e4d565b5f5460ff1660ff16600214611d155760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c0a565b81611d885760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c0a565b609e545f90815260ab6020526040902054611db157609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7e91906156bc565b611eca5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a85415611f1a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611f22614002565b5f4915611f715760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c0a565b5f611f826116b6602084018461563b565b5090505f611f94826001015160c01c90565b611f9f9060016155dd565b5f81815260ad60205260409020549091506120225760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015612086573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120aa9190615603565b6120b491906155dd565b101561211c575f6120cb608085016060860161561a565b61ffff161161211c5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b61213483335f84815260ad602052604090205461424d565b505050565b612141613e4d565b6001600160a01b0381165f908152609f602052604090205460ff166121a85760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c0a565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c65565b6121fe613e4d565b6122075f614962565b565b5f54610100900460ff161580801561222757505f54600160ff909116105b806122405750303b15801561224057505f5460ff166001145b6122b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805460ff1916600117905580156122d3575f805461ff0019166101001790555b6001600160a01b03861615806122f057506001600160a01b038516155b15612327576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871661237d5760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c0a565b6123856149cb565b61238d614a4f565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612509575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61251a613e4d565b6001600160a01b038116158015906125405750609c546001600160a01b03828116911614155b61258c5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c0a565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6125fd613e4d565b5f8111801561260d575060648111155b801561261b575060a9548114155b6126675760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c0a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c05565b60a854156126f55760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6126fd614002565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612769573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278d91906156bc565b6127d95760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b5f806127e58686613ea7565b915091505f6127f8836001015160c01c90565b5f81815260a1602052604090205490915082146128575760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b612860816137ce565b6128ac5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916128e8916155dd565b11612967575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526129629183916001600160a01b031690614ad3565b612509565b6129728386866147af565b61250981336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614c32565b6129ba613e4d565b60aa80545f9091556129cc8282614cfe565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c05565b612a13613e4d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612a8a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c0a565b5f80612a968484613ea7565b915091505f612aa9836001015160c01c90565b90508015612af95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c0a565b5f612b05846079015190565b905080612b545760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c0a565b600984015160c01c15612ba95760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c0a565b5f612bb5856019015190565b03612c025760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c0a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c2e856039015190565b14612c7b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c0a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612da88686613ea7565b915091505f612dbb836001015160c01c90565b5f81815260a160205260409020549091508214612e1a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6125098386866147af565b612e2d613e4d565b8015612f3157612e3b614da3565b60a65460ff1615612ef05760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612e8f9084906155dd565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f39614dfd565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f13565b50565b612f6b613e4d565b5f81118015612f7c575060ac548114155b612fc85760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c0a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c05565b335f908152609f602052604090205460ff166130645760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c0a565b60a854156130b45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6130bc614002565b60a65460ff161561310f5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c0a565b8167ffffffffffffffff16609d541061316a5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a1602052604090205481146131d15760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6131e48267ffffffffffffffff1661189a565b6132305760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132ab5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a26020526040902060010154421061333b5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c0a565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190615603565b3410156133fe5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161351691815260200190565b60405180910390a35f609d54600161352e91906155dd565b90505b609e548111613586578267ffffffffffffffff168114613574576099545f82815260a260205260408120600101805490919061356e9084906155dd565b90915550505b8061357e816156d7565b915050613531565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135b857505f5460ff8083169116105b61362a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055613645613e4d565b815f036136945760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c0a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b335f90815260a560205260408120549081900361376e5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c0a565b335f90815260a560205260408120556137878282614cfe565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137c291815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118c25750505f90815260a46020526040902060030154610100900460ff161590565b613820613e4d565b5f8111801561383157506098548114155b61387d5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c0a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c05565b6138c3613e4d565b6001600160a01b03811661393f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c0a565b612f6081614962565b5f54600490610100900460ff1615801561396857505f5460ff8083169116105b6139da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff8316176101001790556139f5613e4d565b6001600160a01b03821615801590613a1657505f826001600160a01b03163b115b613a625760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c0a565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90613ac6908490614e36565b905060a081901c15613b1a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610c0a565b6040515f602482018190528291613bab908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052614e36565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f90613c12908790614e36565b90506001600160a01b0383163014613c6c5760405162461bcd60e51b815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610c0a565b81158015613c7957505f81115b613cc55760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610c0a565b609d54609e5414613d185760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c0a565b60a85415613d685760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560975490516001600160a01b03898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861617905550505f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6033546001600160a01b031633146122075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c0a565b5f805f613eb48585614ebf565b90505f8160ff165f03613ed557613ecb8686614f2f565b9094509050613f41565b8160ff1660011480613eea57508160ff166002145b15613ef957613ecb8686614f98565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c0a565b808420925050509250929050565b5f81815260a260205260409020600301546001600160a01b031680613f72575050565b6001600160a01b0381165f90815260ae602052604090205480613fd75760405162461bcd60e51b815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610c0a565b613fe26001826155f0565b6001600160a01b039092165f90815260ae60205260409020919091555050565b60655460ff16156122075760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c0a565b805f03614060575050565b8082035f5b8281101561410c5761010081840381111561407f57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b1580156140e2575f80fd5b505af11580156140f4573d5f803e3d5ffd5b50505050610100830192505061010081019050614065565b50505050565b5f816002036141a1575f6040515f5b80498061412e575061413d565b60208202830152600101614121565b60208102808320920160405290925090508061419b5760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c0a565b50919050565b600149156142175760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c0a565b5f4915614225575f496118c2565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261425c602085018561569c565b60ff1611156142ad5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c0a565b60808301356142fe5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c0a565b60a083013561434f5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c0a565b5f806143616116b6602087018761563b565b915091505f614374836001015160c01c90565b90505f60a1816143858460016155dd565b81526020019081526020015f2054146143e05760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c0a565b609e5481146144315760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461448d5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c0a565b5f81815260ab60205260409020546080870135146144ed5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f6144fc846011015160c01c90565b90505f61452861451260608a0160408b0161570e565b61452260808b0160608c0161561a565b84614feb565b905061453a6080890160608a0161561a565b60019384019361ffff91909116929092019160f99061455c60208b018b61569c565b60ff161061456957506101015b60408051828101909152955061458e8661458660208c018c61569c565b60ff1661502f565b60c084901b60018701526145bc866145ac60808c0160608d0161561a565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161460c60208b018b61569c565b60ff161061463e5761463e8661462860608c0160408d0161570e565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156146a75760a7545f90815260a46020526040902060020154609954429161469a916155dd565b6146a491906155f0565b90505b604051806080016040528042815260200182609854426146c791906155dd565b6146d191906155dd565b81526020016146e660608d0160408e0161570e565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561476589615036565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b806147fc5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c0a565b5f61480b846001015160c01c90565b90505f614819856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614848876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a84861490a885160f81c90565b858888866040518663ffffffff1660e01b815260040161492e959493929190615727565b5f6040518083038186803b158015614944575f80fd5b505afa158015614956573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16614a475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b612207615075565b5f54610100900460ff16614acb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6122076150fd565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614b5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b7e9190615603565b5f86815260a46020526040902060010154909150614b9d9082906155dd565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a590915281208054909190614bdc9084906155dd565b9091555050604051614bef90849061578a565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614c5690846157b6565b614c6091906157cd565b9050614c6c81836155f0565b60aa5f828254614c7c91906155dd565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614ca89084906155dd565b9091555050604051614cbb90849061578a565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611b62575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614d4d576040519150601f19603f3d011682016040523d82523d5f602084013e614d52565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c0a565b614dab614002565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614de03390565b6040516001600160a01b03909116815260200160405180910390a1565b614e05615182565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614de0565b5f805f805f855160208701885afa91503d905060208114821615614e5e5760205f803e5f5192505b818015614e6b5750806020145b614eb75760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610c0a565b505092915050565b5f81614f0d5760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c0a565b82825f818110614f1f57614f1f615805565b919091013560f81c949350505050565b5f8160f9811015614f825760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c0a565b6040519150808483378082016040529250929050565b5f816101018114614f825760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c0a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f9181016150208161ffff8716866151d4565b82900390912095945050505050565b8082535050565b6001600160a01b03811615612f60576001600160a01b0381165f90815260ae6020526040812080546001929061506d9084906155dd565b909155505050565b5f54610100900460ff166150f15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6065805460ff19169055565b5f54610100900460ff166151795760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b61220733614962565b60655460ff166122075760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c0a565b5f825f036151e3575082615296565b609b546001600160a01b03165f5b84811015615290576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015615257573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061527b9190615603565b875250602090950194600193840193016151f1565b50849150505b9392505050565b5f602082840312156152ad575f80fd5b5035919050565b80356001600160a01b0381168114614248575f80fd5b5f602082840312156152da575f80fd5b615296826152b4565b5f8083601f8401126152f3575f80fd5b50813567ffffffffffffffff81111561530a575f80fd5b602083019150836020828501011115615321575f80fd5b9250929050565b5f805f6040848603121561533a575f80fd5b833567ffffffffffffffff811115615350575f80fd5b61535c868287016152e3565b909790965060209590950135949350505050565b5f8060208385031215615381575f80fd5b823567ffffffffffffffff811115615397575f80fd5b6153a3858286016152e3565b90969095509350505050565b5f60e0828403121561419b575f80fd5b5f805f805f606086880312156153d3575f80fd5b853567ffffffffffffffff808211156153ea575f80fd5b6153f689838a016153af565b9650602088013591508082111561540b575f80fd5b61541789838a016152e3565b9096509450604088013591508082111561542f575f80fd5b5061543c888289016152e3565b969995985093965092949392505050565b5f6020828403121561545d575f80fd5b813567ffffffffffffffff811115615473575f80fd5b61547f848285016153af565b949350505050565b5f805f805f8060c0878903121561549c575f80fd5b6154a5876152b4565b95506154b3602088016152b4565b94506154c1604088016152b4565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156154f5575f80fd5b843567ffffffffffffffff8082111561550c575f80fd5b615518888389016152e3565b90965094506020870135915080821115615530575f80fd5b5061553d878288016152e3565b95989497509550505050565b8015158114612f60575f80fd5b5f60208284031215615566575f80fd5b813561529681615549565b803567ffffffffffffffff81168114614248575f80fd5b5f8060408385031215615599575f80fd5b6155a283615571565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118c2576118c26155b0565b818103818111156118c2576118c26155b0565b5f60208284031215615613575f80fd5b5051919050565b5f6020828403121561562a575f80fd5b813561ffff81168114615296575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261566e575f80fd5b83018035915067ffffffffffffffff821115615688575f80fd5b602001915036819003821315615321575f80fd5b5f602082840312156156ac575f80fd5b813560ff81168114615296575f80fd5b5f602082840312156156cc575f80fd5b815161529681615549565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615707576157076155b0565b5060010190565b5f6020828403121561571e575f80fd5b61529682615571565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156157a9576020818601810151858301520161578f565b505f920191825250919050565b80820281158282048414176118c2576118c26155b0565b5f82615800577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bin/submitter_deployed.hex b/bindings/bin/submitter_deployed.hex new file mode 100644 index 000000000..b62e9ebe8 --- /dev/null +++ b/bindings/bin/submitter_deployed.hex @@ -0,0 +1 @@ +0x60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd111461044a578063d13f90b414610469578063ec5ffac214610488578063f2fde38b1461049d575f80fd5b8063bfa02ba9146103ed578063c36f41e21461040c578063c96be4cb1461042b575f80fd5b8063ab8c53dc116100b7578063ab8c53dc1461037c578063b2dd5c0714610391578063bbfefd38146103bf575f80fd5b80639f8a13d71461030f578063a3066aab1461033e578063a4f209b01461035d575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac366004611cca565b6104bc565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f5366004611cea565b6105b4565b348015610205575f80fd5b506101b1610214366004611cea565b61065a565b6101b1610700565b34801561022c575f80fd5b506101c861023b366004611cca565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c8610266366004611cca565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b1610291366004611cca565b61086e565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c5366004611cca565b610a06565b3480156102d5575f80fd5b506101b1610b45565b3480156102e9575f80fd5b506033546001600160a01b03165b6040516001600160a01b0390911681526020016101d2565b34801561031a575f80fd5b5061032e610329366004611cca565b610b56565b60405190151581526020016101d2565b348015610349575f80fd5b506101b1610358366004611cca565b610bc0565b348015610368575f80fd5b506101b1610377366004611cea565b610ce5565b348015610387575f80fd5b506101c8609b5481565b34801561039c575f80fd5b5061032e6103ab366004611cca565b609c6020525f908152604090205460ff1681565b3480156103ca575f80fd5b5061032e6103d9366004611cca565b609e6020525f908152604090205460ff1681565b3480156103f8575f80fd5b506097546102f7906001600160a01b031681565b348015610417575f80fd5b506101b1610426366004611cca565b610d98565b348015610436575f80fd5b506101c8610445366004611cca565b610ef8565b348015610455575f80fd5b506101b1610464366004611cca565b611064565b348015610474575f80fd5b506101b1610483366004611d01565b611176565b348015610493575f80fd5b506101c860985481565b3480156104a8575f80fd5b506101b16104b7366004611cca565b61158a565b6104c4611617565b6001600160a01b038116158015906104f457506001600160a01b0381165f908152609c602052604090205460ff16155b801561051857506001600160a01b0381165f908152609e602052604090205460ff16155b6105695760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105bc611617565b5f811180156105cd57506098548114155b6106195760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610662611617565b5f8111801561067357506099548114155b6106bf5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610708611671565b335f818152609c602052604090205460ff16801561073e57506001600160a01b0381165f908152609e602052604090205460ff16155b61078a5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609d60205260408120546107ad903490611d77565b90505f341180156107c057506098548110155b61080c5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610560565b6001600160a01b0382165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061086c6001606555565b565b610876611671565b336001600160a01b0382166108cd5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609c602052604090205460ff16801561090c57506001600160a01b0381165f908152609e602052604090205460ff16155b801561092e57506001600160a01b0381165f908152609d602052604090205415155b61097a5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610560565b6001600160a01b038181165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a36109f881836116d1565b50610a036001606555565b50565b610a0e611671565b336001600160a01b038216610a655760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609f602052604090205480610aca5760405162461bcd60e51b815260206004820152600960248201527f6e6f2063726564697400000000000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0382165f908152609f6020526040812055610aec83826116ed565b826001600160a01b0316826001600160a01b03167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610b3191815260200190565b60405180910390a35050610a036001606555565b610b4d611617565b61086c5f61179c565b6001600160a01b0381165f908152609c602052604081205460ff168015610b9557506001600160a01b0382165f908152609e602052604090205460ff16155b8015610bba57506098546001600160a01b0383165f908152609d602052604090205410155b92915050565b610bc8611671565b336001600160a01b038216610c1f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609e602052604090205460ff16610c865760405162461bcd60e51b815260206004820152600b60248201527f6e6f742065786974696e670000000000000000000000000000000000000000006044820152606401610560565b610c8f81611805565b610cdb5760405162461bcd60e51b815260206004820152601760248201527f70656e64696e67206261746368206c696162696c6974790000000000000000006044820152606401610560565b6109f881836118f0565b610ced611617565b5f81118015610cfd575060648111155b8015610d0b5750609a548114155b610d575760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610da0611617565b610da8611671565b6001600160a01b0381165f908152609c602052604090205460ff168015610de757506001600160a01b0381165f908152609e602052604090205460ff16155b610e335760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f818152609c60209081526040808320805460ff19908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a26001600160a01b0381165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b3291610edc91815260200190565b60405180910390a3610eee81826116d1565b610a036001606555565b6097545f906001600160a01b0316336001600160a01b031614610f5d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610560565b610f65611671565b6001600160a01b038216610f7a57505f611055565b6001600160a01b0382165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216600117909155609a54606490610fce9083611d8a565b610fd89190611da1565b9150610fe48282611dd9565b609b5f828254610ff49190611d77565b909155505060975461100f906001600160a01b0316836116ed565b60408051828152602081018490526001600160a01b038516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61105f6001606555565b919050565b61106c611617565b611074611671565b6001600160a01b0381166110ca5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b609b548061111a5760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610560565b5f609b5561112882826116ed565b816001600160a01b03167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161116391815260200190565b60405180910390a250610a036001606555565b5f54610100900460ff161580801561119457505f54600160ff909116105b806111ad5750303b1580156111ad57505f5460ff166001145b61121f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610560565b5f805460ff19166001179055801561125d575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0386166112b35760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610560565b6001600160a01b038516158015906112d457505f856001600160a01b03163b115b6113205760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610560565b5f841161136f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b5f83116113be5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b5f821180156113ce575060648211155b61141a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b611422611aab565b61142a611b2f565b6114338661179c565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611582575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611592611617565b6001600160a01b03811661160e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610560565b610a038161179c565b6033546001600160a01b0316331461086c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610560565b6002606554036116c35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610560565b6002606555565b6001606555565b6116da82611805565b156116e9576116e982826118f0565b5050565b805f036116f8575050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611741576040519150601f19603f3d011682016040523d82523d5f602084013e611746565b606091505b50509050806117975760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610560565b505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6040516001600160a01b03821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a80000000000000000000000000000000000000000000000000000000017815260975482519293506001600160a01b0316915f9182918291829182918761c350fa92503d9150602082148316156118ce5760205f803e505f515b8280156118db5750816020145b80156118e5575080155b979650505050505050565b6001600160a01b0382165f908152609d60209081526040808320805490849055609e9092528220805460ff191690559081900361197957816001600160a01b0316836001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f60405161196c91815260200190565b60405180910390a3505050565b5f826001600160a01b03168261c350906040515f60405180830381858888f193505050503d805f81146119c7576040519150601f19603f3d011682016040523d82523d5f602084013e6119cc565b606091505b505090508015611a2857826001600160a01b0316846001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f4684604051611a1b91815260200190565b60405180910390a3611aa5565b6001600160a01b0384165f908152609f602052604081208054849290611a4f908490611d77565b90915550506001600160a01b0384165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff16611b275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611bb3565b5f54610100900460ff16611bab5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611c38565b5f54610100900460ff16611c2f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c3361179c565b5f54610100900460ff166116ca5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b80356001600160a01b038116811461105f575f80fd5b5f60208284031215611cda575f80fd5b611ce382611cb4565b9392505050565b5f60208284031215611cfa575f80fd5b5035919050565b5f805f805f60a08688031215611d15575f80fd5b611d1e86611cb4565b9450611d2c60208701611cb4565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610bba57610bba611d4a565b8082028115828204841417610bba57610bba611d4a565b5f82611dd4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610bba57610bba611d4a56fea164736f6c6343000818000a diff --git a/bindings/bindings/l1staking.go b/bindings/bindings/l1staking.go deleted file mode 100644 index 6ef653abe..000000000 --- a/bindings/bindings/l1staking.go +++ /dev/null @@ -1,3445 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// L1StakingMetaData contains all meta data concerning the L1Staking contract. -var L1StakingMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"_messenger\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChallengeDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChallengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitAddStakerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitRemoveStakersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"Registered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercentage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercentage\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"StakersRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldStakingValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStakingValue\",\"type\":\"uint256\"}],\"name\":\"StakingValueUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"WhitelistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unlockHeight\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MESSENGER\",\"outputs\":[{\"internalType\":\"contractICrossDomainMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OTHER_STAKING\",\"outputs\":[{\"internalType\":\"contractStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"blsPubkey\",\"type\":\"bytes\"}],\"name\":\"blsKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cleanStakerStore\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"deleteList\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"deleteableHeight\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitAddStaker\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitRemoveStakers\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getActiveStakers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"}],\"name\":\"getStakerBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakers\",\"outputs\":[{\"internalType\":\"address[255]\",\"name\":\"\",\"type\":\"address[255]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"getStakersBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"name\":\"getStakersFromBitmap\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"stakerAddrs\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rollupContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_lockBlocks\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isActiveStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStakerInDeleteList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"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\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"removeStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"removedList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"removed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sequencersBitmap\",\"type\":\"uint256\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakerIndexes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"stakerSet\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakers\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"tmPubkey\",\"type\":\"bytes32\"}],\"name\":\"tmKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitAddStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitRemoveStakers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"}],\"name\":\"updateStakingValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"updateWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"verifySignature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"whitelist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"inWhitelist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalLockBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"withdrawals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60c060405234801562000010575f80fd5b5060405162003e1d38038062003e1d833981016040819052620000339162000127565b6001600160a01b03811660805273530000000000000000000000000000000000001560a0526200006262000069565b5062000156565b5f54610100900460ff1615620000d55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161462000125575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000138575f80fd5b81516001600160a01b03811681146200014f575f80fd5b9392505050565b60805160a051613c826200019b5f395f8181610664015281816129530152612bc701525f818161043c01528181610701015281816129240152612b980152613c825ff3fe6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a", -} - -// L1StakingABI is the input ABI used to generate the binding from. -// Deprecated: Use L1StakingMetaData.ABI instead. -var L1StakingABI = L1StakingMetaData.ABI - -// L1StakingBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use L1StakingMetaData.Bin instead. -var L1StakingBin = L1StakingMetaData.Bin - -// DeployL1Staking deploys a new Ethereum contract, binding an instance of L1Staking to it. -func DeployL1Staking(auth *bind.TransactOpts, backend bind.ContractBackend, _messenger common.Address) (common.Address, *types.Transaction, *L1Staking, error) { - parsed, err := L1StakingMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(L1StakingBin), backend, _messenger) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil -} - -// L1Staking is an auto generated Go binding around an Ethereum contract. -type L1Staking struct { - L1StakingCaller // Read-only binding to the contract - L1StakingTransactor // Write-only binding to the contract - L1StakingFilterer // Log filterer for contract events -} - -// L1StakingCaller is an auto generated read-only Go binding around an Ethereum contract. -type L1StakingCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingTransactor is an auto generated write-only Go binding around an Ethereum contract. -type L1StakingTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type L1StakingFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type L1StakingSession struct { - Contract *L1Staking // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// L1StakingCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type L1StakingCallerSession struct { - Contract *L1StakingCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// L1StakingTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type L1StakingTransactorSession struct { - Contract *L1StakingTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// L1StakingRaw is an auto generated low-level Go binding around an Ethereum contract. -type L1StakingRaw struct { - Contract *L1Staking // Generic contract binding to access the raw methods on -} - -// L1StakingCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type L1StakingCallerRaw struct { - Contract *L1StakingCaller // Generic read-only contract binding to access the raw methods on -} - -// L1StakingTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type L1StakingTransactorRaw struct { - Contract *L1StakingTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewL1Staking creates a new instance of L1Staking, bound to a specific deployed contract. -func NewL1Staking(address common.Address, backend bind.ContractBackend) (*L1Staking, error) { - contract, err := bindL1Staking(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil -} - -// NewL1StakingCaller creates a new read-only instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingCaller(address common.Address, caller bind.ContractCaller) (*L1StakingCaller, error) { - contract, err := bindL1Staking(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &L1StakingCaller{contract: contract}, nil -} - -// NewL1StakingTransactor creates a new write-only instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingTransactor(address common.Address, transactor bind.ContractTransactor) (*L1StakingTransactor, error) { - contract, err := bindL1Staking(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &L1StakingTransactor{contract: contract}, nil -} - -// NewL1StakingFilterer creates a new log filterer instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingFilterer(address common.Address, filterer bind.ContractFilterer) (*L1StakingFilterer, error) { - contract, err := bindL1Staking(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &L1StakingFilterer{contract: contract}, nil -} - -// bindL1Staking binds a generic wrapper to an already deployed contract. -func bindL1Staking(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := L1StakingMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_L1Staking *L1StakingRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _L1Staking.Contract.L1StakingCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_L1Staking *L1StakingRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.Contract.L1StakingTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_L1Staking *L1StakingRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _L1Staking.Contract.L1StakingTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_L1Staking *L1StakingCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _L1Staking.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_L1Staking *L1StakingTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_L1Staking *L1StakingTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _L1Staking.Contract.contract.Transact(opts, method, params...) -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingCaller) MESSENGER(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "MESSENGER") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingSession) MESSENGER() (common.Address, error) { - return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingCallerSession) MESSENGER() (common.Address, error) { - return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingCaller) OTHERSTAKING(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "OTHER_STAKING") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingSession) OTHERSTAKING() (common.Address, error) { - return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingCallerSession) OTHERSTAKING() (common.Address, error) { - return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCaller) BlsKeys(opts *bind.CallOpts, blsPubkey []byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "blsKeys", blsPubkey) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingSession) BlsKeys(blsPubkey []byte) (bool, error) { - return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCallerSession) BlsKeys(blsPubkey []byte) (bool, error) { - return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "challengeDeposit") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingSession) ChallengeDeposit() (*big.Int, error) { - return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) ChallengeDeposit() (*big.Int, error) { - return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingCaller) DeleteList(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "deleteList", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingSession) DeleteList(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingCallerSession) DeleteList(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingCaller) DeleteableHeight(opts *bind.CallOpts, stakerAddr common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "deleteableHeight", stakerAddr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { - return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingCallerSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { - return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingCaller) GasLimitAddStaker(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "gasLimitAddStaker") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingSession) GasLimitAddStaker() (*big.Int, error) { - return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) GasLimitAddStaker() (*big.Int, error) { - return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingCaller) GasLimitRemoveStakers(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "gasLimitRemoveStakers") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingSession) GasLimitRemoveStakers() (*big.Int, error) { - return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) GasLimitRemoveStakers() (*big.Int, error) { - return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingCaller) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getActiveStakers") - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingSession) GetActiveStakers() ([]common.Address, error) { - return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingCallerSession) GetActiveStakers() ([]common.Address, error) { - return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCaller) GetStakerBitmap(opts *bind.CallOpts, _staker common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakerBitmap", _staker) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCallerSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingCaller) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakers") - - if err != nil { - return *new([255]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([255]common.Address)).(*[255]common.Address) - - return out0, err - -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingSession) GetStakers() ([255]common.Address, error) { - return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingCallerSession) GetStakers() ([255]common.Address, error) { - return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCaller) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakersBitmap", _stakers) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCallerSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingCaller) GetStakersFromBitmap(opts *bind.CallOpts, bitmap *big.Int) ([]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakersFromBitmap", bitmap) - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { - return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingCallerSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { - return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsActiveStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isActiveStaker", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsActiveStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsActiveStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isStaker", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsStakerInDeleteList(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isStakerInDeleteList", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsStakerInDeleteList(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsStakerInDeleteList(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingCaller) Messenger(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "messenger") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingSession) Messenger() (common.Address, error) { - return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingCallerSession) Messenger() (common.Address, error) { - return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingSession) Owner() (common.Address, error) { - return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingCallerSession) Owner() (common.Address, error) { - return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingCaller) RemovedList(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "removedList", stakerAddr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingSession) RemovedList(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingCallerSession) RemovedList(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "rewardPercentage") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingSession) RewardPercentage() (*big.Int, error) { - return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) RewardPercentage() (*big.Int, error) { - return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "rollupContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingSession) RollupContract() (common.Address, error) { - return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingCallerSession) RollupContract() (common.Address, error) { - return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "slashRemaining") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingSession) SlashRemaining() (*big.Int, error) { - return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) SlashRemaining() (*big.Int, error) { - return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingCaller) StakerIndexes(opts *bind.CallOpts, stakerAddr common.Address) (uint8, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakerIndexes", stakerAddr) - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { - return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingCallerSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { - return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingCaller) StakerSet(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakerSet", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingSession) StakerSet(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingCallerSession) StakerSet(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingCaller) Stakers(opts *bind.CallOpts, stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakers", stakerAddr) - - outstruct := new(struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte - }) - if err != nil { - return *outstruct, err - } - - outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.TmKey = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - outstruct.BlsKey = *abi.ConvertType(out[2], new([]byte)).(*[]byte) - - return *outstruct, err - -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingSession) Stakers(stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingCallerSession) Stakers(stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingCaller) StakingValue(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakingValue") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingSession) StakingValue() (*big.Int, error) { - return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) StakingValue() (*big.Int, error) { - return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCaller) TmKeys(opts *bind.CallOpts, tmPubkey [32]byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "tmKeys", tmPubkey) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingSession) TmKeys(tmPubkey [32]byte) (bool, error) { - return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCallerSession) TmKeys(tmPubkey [32]byte) (bool, error) { - return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingCaller) VerifySignature(opts *bind.CallOpts, arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "verifySignature", arg0, arg1, arg2, arg3) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingCallerSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingCaller) Whitelist(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "whitelist", stakerAddr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingSession) Whitelist(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingCallerSession) Whitelist(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingCaller) WithdrawalLockBlocks(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "withdrawalLockBlocks") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingSession) WithdrawalLockBlocks() (*big.Int, error) { - return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) WithdrawalLockBlocks() (*big.Int, error) { - return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingCaller) Withdrawals(opts *bind.CallOpts, staker common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "withdrawals", staker) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingSession) Withdrawals(staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingCallerSession) Withdrawals(staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "claimSlashRemaining", receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "claimWithdrawal", receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingTransactor) CleanStakerStore(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "cleanStakerStore") -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingSession) CleanStakerStore() (*types.Transaction, error) { - return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingTransactorSession) CleanStakerStore() (*types.Transaction, error) { - return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactor) Initialize(opts *bind.TransactOpts, _rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "initialize", _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactorSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingTransactor) Register(opts *bind.TransactOpts, tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "register", tmKey, blsKey) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingTransactorSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingTransactor) RemoveStaker(opts *bind.TransactOpts, _stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "removeStaker", _stakers) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingTransactorSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "renounceOwnership") -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingSession) RenounceOwnership() (*types.Transaction, error) { - return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingTransactorSession) RenounceOwnership() (*types.Transaction, error) { - return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingTransactor) Slash(opts *bind.TransactOpts, sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "slash", sequencersBitmap) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingTransactorSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "transferOwnership", newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, _challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateChallengeDeposit", _challengeDeposit) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingTransactor) UpdateGasLimitAddStaker(opts *bind.TransactOpts, _gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateGasLimitAddStaker", _gasLimitAdd) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactor) UpdateGasLimitRemoveStakers(opts *bind.TransactOpts, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateGasLimitRemoveStakers", _gasLimitRemove) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, _rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateRewardPercentage", _rewardPercentage) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingTransactor) UpdateStakingValue(opts *bind.TransactOpts, _stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateStakingValue", _stakingValue) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingTransactor) UpdateWhitelist(opts *bind.TransactOpts, add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateWhitelist", add, remove) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "withdraw") -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingSession) Withdraw() (*types.Transaction, error) { - return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingTransactorSession) Withdraw() (*types.Transaction, error) { - return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) -} - -// L1StakingChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the L1Staking contract. -type L1StakingChallengeDepositUpdatedIterator struct { - Event *L1StakingChallengeDepositUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingChallengeDepositUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingChallengeDepositUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingChallengeDepositUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the L1Staking contract. -type L1StakingChallengeDepositUpdated struct { - OldChallengeDeposit *big.Int - NewChallengeDeposit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*L1StakingChallengeDepositUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return &L1StakingChallengeDepositUpdatedIterator{contract: _L1Staking.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil -} - -// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingChallengeDepositUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingChallengeDepositUpdated) - if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) ParseChallengeDepositUpdated(log types.Log) (*L1StakingChallengeDepositUpdated, error) { - event := new(L1StakingChallengeDepositUpdated) - if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingClaimedIterator is returned from FilterClaimed and is used to iterate over the raw logs and unpacked data for Claimed events raised by the L1Staking contract. -type L1StakingClaimedIterator struct { - Event *L1StakingClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingClaimed represents a Claimed event raised by the L1Staking contract. -type L1StakingClaimed struct { - Staker common.Address - Receiver common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterClaimed is a free log retrieval operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) FilterClaimed(opts *bind.FilterOpts, staker []common.Address) (*L1StakingClaimedIterator, error) { - - var stakerRule []interface{} - for _, stakerItem := range staker { - stakerRule = append(stakerRule, stakerItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Claimed", stakerRule) - if err != nil { - return nil, err - } - return &L1StakingClaimedIterator{contract: _L1Staking.contract, event: "Claimed", logs: logs, sub: sub}, nil -} - -// WatchClaimed is a free log subscription operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) WatchClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingClaimed, staker []common.Address) (event.Subscription, error) { - - var stakerRule []interface{} - for _, stakerItem := range staker { - stakerRule = append(stakerRule, stakerItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Claimed", stakerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseClaimed is a log parse operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) ParseClaimed(log types.Log) (*L1StakingClaimed, error) { - event := new(L1StakingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingGasLimitAddStakerUpdatedIterator is returned from FilterGasLimitAddStakerUpdated and is used to iterate over the raw logs and unpacked data for GasLimitAddStakerUpdated events raised by the L1Staking contract. -type L1StakingGasLimitAddStakerUpdatedIterator struct { - Event *L1StakingGasLimitAddStakerUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitAddStakerUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitAddStakerUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingGasLimitAddStakerUpdated represents a GasLimitAddStakerUpdated event raised by the L1Staking contract. -type L1StakingGasLimitAddStakerUpdated struct { - OldGasLimit *big.Int - NewGasLimit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterGasLimitAddStakerUpdated is a free log retrieval operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) FilterGasLimitAddStakerUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitAddStakerUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitAddStakerUpdated") - if err != nil { - return nil, err - } - return &L1StakingGasLimitAddStakerUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitAddStakerUpdated", logs: logs, sub: sub}, nil -} - -// WatchGasLimitAddStakerUpdated is a free log subscription operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) WatchGasLimitAddStakerUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitAddStakerUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitAddStakerUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingGasLimitAddStakerUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseGasLimitAddStakerUpdated is a log parse operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) ParseGasLimitAddStakerUpdated(log types.Log) (*L1StakingGasLimitAddStakerUpdated, error) { - event := new(L1StakingGasLimitAddStakerUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingGasLimitRemoveStakersUpdatedIterator is returned from FilterGasLimitRemoveStakersUpdated and is used to iterate over the raw logs and unpacked data for GasLimitRemoveStakersUpdated events raised by the L1Staking contract. -type L1StakingGasLimitRemoveStakersUpdatedIterator struct { - Event *L1StakingGasLimitRemoveStakersUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitRemoveStakersUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitRemoveStakersUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingGasLimitRemoveStakersUpdated represents a GasLimitRemoveStakersUpdated event raised by the L1Staking contract. -type L1StakingGasLimitRemoveStakersUpdated struct { - OldGasLimit *big.Int - NewGasLimit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterGasLimitRemoveStakersUpdated is a free log retrieval operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) FilterGasLimitRemoveStakersUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitRemoveStakersUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitRemoveStakersUpdated") - if err != nil { - return nil, err - } - return &L1StakingGasLimitRemoveStakersUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitRemoveStakersUpdated", logs: logs, sub: sub}, nil -} - -// WatchGasLimitRemoveStakersUpdated is a free log subscription operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) WatchGasLimitRemoveStakersUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitRemoveStakersUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitRemoveStakersUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingGasLimitRemoveStakersUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseGasLimitRemoveStakersUpdated is a log parse operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) ParseGasLimitRemoveStakersUpdated(log types.Log) (*L1StakingGasLimitRemoveStakersUpdated, error) { - event := new(L1StakingGasLimitRemoveStakersUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the L1Staking contract. -type L1StakingInitializedIterator struct { - Event *L1StakingInitialized // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingInitializedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingInitializedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingInitializedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingInitialized represents a Initialized event raised by the L1Staking contract. -type L1StakingInitialized struct { - Version uint8 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) FilterInitialized(opts *bind.FilterOpts) (*L1StakingInitializedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return &L1StakingInitializedIterator{contract: _L1Staking.contract, event: "Initialized", logs: logs, sub: sub}, nil -} - -// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *L1StakingInitialized) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingInitialized) - if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) ParseInitialized(log types.Log) (*L1StakingInitialized, error) { - event := new(L1StakingInitialized) - if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the L1Staking contract. -type L1StakingOwnershipTransferredIterator struct { - Event *L1StakingOwnershipTransferred // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingOwnershipTransferredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingOwnershipTransferredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingOwnershipTransferred represents a OwnershipTransferred event raised by the L1Staking contract. -type L1StakingOwnershipTransferred struct { - PreviousOwner common.Address - NewOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*L1StakingOwnershipTransferredIterator, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return &L1StakingOwnershipTransferredIterator{contract: _L1Staking.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *L1StakingOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingOwnershipTransferred) - if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) ParseOwnershipTransferred(log types.Log) (*L1StakingOwnershipTransferred, error) { - event := new(L1StakingOwnershipTransferred) - if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingRegisteredIterator is returned from FilterRegistered and is used to iterate over the raw logs and unpacked data for Registered events raised by the L1Staking contract. -type L1StakingRegisteredIterator struct { - Event *L1StakingRegistered // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingRegisteredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingRegisteredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingRegisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingRegistered represents a Registered event raised by the L1Staking contract. -type L1StakingRegistered struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRegistered is a free log retrieval operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) FilterRegistered(opts *bind.FilterOpts) (*L1StakingRegisteredIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Registered") - if err != nil { - return nil, err - } - return &L1StakingRegisteredIterator{contract: _L1Staking.contract, event: "Registered", logs: logs, sub: sub}, nil -} - -// WatchRegistered is a free log subscription operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) WatchRegistered(opts *bind.WatchOpts, sink chan<- *L1StakingRegistered) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Registered") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingRegistered) - if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRegistered is a log parse operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) ParseRegistered(log types.Log) (*L1StakingRegistered, error) { - event := new(L1StakingRegistered) - if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the L1Staking contract. -type L1StakingRewardPercentageUpdatedIterator struct { - Event *L1StakingRewardPercentageUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingRewardPercentageUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingRewardPercentageUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingRewardPercentageUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the L1Staking contract. -type L1StakingRewardPercentageUpdated struct { - OldPercentage *big.Int - NewPercentage *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*L1StakingRewardPercentageUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return &L1StakingRewardPercentageUpdatedIterator{contract: _L1Staking.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil -} - -// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingRewardPercentageUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingRewardPercentageUpdated) - if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) ParseRewardPercentageUpdated(log types.Log) (*L1StakingRewardPercentageUpdated, error) { - event := new(L1StakingRewardPercentageUpdated) - if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the L1Staking contract. -type L1StakingSlashRemainingClaimedIterator struct { - Event *L1StakingSlashRemainingClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingSlashRemainingClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingSlashRemainingClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingSlashRemainingClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the L1Staking contract. -type L1StakingSlashRemainingClaimed struct { - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts) (*L1StakingSlashRemainingClaimedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "SlashRemainingClaimed") - if err != nil { - return nil, err - } - return &L1StakingSlashRemainingClaimedIterator{contract: _L1Staking.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil -} - -// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashRemainingClaimed) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "SlashRemainingClaimed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingSlashRemainingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) ParseSlashRemainingClaimed(log types.Log) (*L1StakingSlashRemainingClaimed, error) { - event := new(L1StakingSlashRemainingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the L1Staking contract. -type L1StakingSlashedIterator struct { - Event *L1StakingSlashed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingSlashedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingSlashedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingSlashedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingSlashed represents a Slashed event raised by the L1Staking contract. -type L1StakingSlashed struct { - Stakers []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashed is a free log retrieval operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) FilterSlashed(opts *bind.FilterOpts) (*L1StakingSlashedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Slashed") - if err != nil { - return nil, err - } - return &L1StakingSlashedIterator{contract: _L1Staking.contract, event: "Slashed", logs: logs, sub: sub}, nil -} - -// WatchSlashed is a free log subscription operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashed) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Slashed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingSlashed) - if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashed is a log parse operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) ParseSlashed(log types.Log) (*L1StakingSlashed, error) { - event := new(L1StakingSlashed) - if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingStakersRemovedIterator is returned from FilterStakersRemoved and is used to iterate over the raw logs and unpacked data for StakersRemoved events raised by the L1Staking contract. -type L1StakingStakersRemovedIterator struct { - Event *L1StakingStakersRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingStakersRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingStakersRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingStakersRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingStakersRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingStakersRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingStakersRemoved represents a StakersRemoved event raised by the L1Staking contract. -type L1StakingStakersRemoved struct { - Stakers []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStakersRemoved is a free log retrieval operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) FilterStakersRemoved(opts *bind.FilterOpts) (*L1StakingStakersRemovedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakersRemoved") - if err != nil { - return nil, err - } - return &L1StakingStakersRemovedIterator{contract: _L1Staking.contract, event: "StakersRemoved", logs: logs, sub: sub}, nil -} - -// WatchStakersRemoved is a free log subscription operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) WatchStakersRemoved(opts *bind.WatchOpts, sink chan<- *L1StakingStakersRemoved) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakersRemoved") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingStakersRemoved) - if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStakersRemoved is a log parse operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) ParseStakersRemoved(log types.Log) (*L1StakingStakersRemoved, error) { - event := new(L1StakingStakersRemoved) - if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingStakingValueUpdatedIterator is returned from FilterStakingValueUpdated and is used to iterate over the raw logs and unpacked data for StakingValueUpdated events raised by the L1Staking contract. -type L1StakingStakingValueUpdatedIterator struct { - Event *L1StakingStakingValueUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingStakingValueUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingStakingValueUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingStakingValueUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingStakingValueUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingStakingValueUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingStakingValueUpdated represents a StakingValueUpdated event raised by the L1Staking contract. -type L1StakingStakingValueUpdated struct { - OldStakingValue *big.Int - NewStakingValue *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStakingValueUpdated is a free log retrieval operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) FilterStakingValueUpdated(opts *bind.FilterOpts) (*L1StakingStakingValueUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakingValueUpdated") - if err != nil { - return nil, err - } - return &L1StakingStakingValueUpdatedIterator{contract: _L1Staking.contract, event: "StakingValueUpdated", logs: logs, sub: sub}, nil -} - -// WatchStakingValueUpdated is a free log subscription operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) WatchStakingValueUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingStakingValueUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakingValueUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingStakingValueUpdated) - if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStakingValueUpdated is a log parse operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) ParseStakingValueUpdated(log types.Log) (*L1StakingStakingValueUpdated, error) { - event := new(L1StakingStakingValueUpdated) - if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingWhitelistUpdatedIterator is returned from FilterWhitelistUpdated and is used to iterate over the raw logs and unpacked data for WhitelistUpdated events raised by the L1Staking contract. -type L1StakingWhitelistUpdatedIterator struct { - Event *L1StakingWhitelistUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingWhitelistUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingWhitelistUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingWhitelistUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingWhitelistUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingWhitelistUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingWhitelistUpdated represents a WhitelistUpdated event raised by the L1Staking contract. -type L1StakingWhitelistUpdated struct { - Add []common.Address - Remove []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWhitelistUpdated is a free log retrieval operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) FilterWhitelistUpdated(opts *bind.FilterOpts) (*L1StakingWhitelistUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "WhitelistUpdated") - if err != nil { - return nil, err - } - return &L1StakingWhitelistUpdatedIterator{contract: _L1Staking.contract, event: "WhitelistUpdated", logs: logs, sub: sub}, nil -} - -// WatchWhitelistUpdated is a free log subscription operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) WatchWhitelistUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingWhitelistUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "WhitelistUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingWhitelistUpdated) - if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWhitelistUpdated is a log parse operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) ParseWhitelistUpdated(log types.Log) (*L1StakingWhitelistUpdated, error) { - event := new(L1StakingWhitelistUpdated) - if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingWithdrawnIterator is returned from FilterWithdrawn and is used to iterate over the raw logs and unpacked data for Withdrawn events raised by the L1Staking contract. -type L1StakingWithdrawnIterator struct { - Event *L1StakingWithdrawn // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingWithdrawnIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingWithdrawn) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingWithdrawn) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingWithdrawnIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingWithdrawnIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingWithdrawn represents a Withdrawn event raised by the L1Staking contract. -type L1StakingWithdrawn struct { - Addr common.Address - UnlockHeight *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawn is a free log retrieval operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) FilterWithdrawn(opts *bind.FilterOpts, addr []common.Address) (*L1StakingWithdrawnIterator, error) { - - var addrRule []interface{} - for _, addrItem := range addr { - addrRule = append(addrRule, addrItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Withdrawn", addrRule) - if err != nil { - return nil, err - } - return &L1StakingWithdrawnIterator{contract: _L1Staking.contract, event: "Withdrawn", logs: logs, sub: sub}, nil -} - -// WatchWithdrawn is a free log subscription operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) WatchWithdrawn(opts *bind.WatchOpts, sink chan<- *L1StakingWithdrawn, addr []common.Address) (event.Subscription, error) { - - var addrRule []interface{} - for _, addrItem := range addr { - addrRule = append(addrRule, addrItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Withdrawn", addrRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingWithdrawn) - if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawn is a log parse operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) ParseWithdrawn(log types.Log) (*L1StakingWithdrawn, error) { - event := new(L1StakingWithdrawn) - if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/bindings/bindings/l1staking_more.go b/bindings/bindings/l1staking_more.go deleted file mode 100644 index c3a973380..000000000 --- a/bindings/bindings/l1staking_more.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "encoding/json" - - "morph-l2/bindings/solc" -) - -const L1StakingStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1027_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakingValue\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawalLockBlocks\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitAddStaker\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitRemoveStakers\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_uint256\"},{\"astId\":1013,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"whitelist\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"removedList\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerSet\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_address)1025_storage\"},{\"astId\":1017,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerIndexes\",\"offset\":0,\"slot\":\"415\",\"type\":\"t_mapping(t_address,t_uint8)\"},{\"astId\":1018,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteList\",\"offset\":0,\"slot\":\"416\",\"type\":\"t_array(t_address)dyn_storage\"},{\"astId\":1019,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteableHeight\",\"offset\":0,\"slot\":\"417\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1020,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakers\",\"offset\":0,\"slot\":\"418\",\"type\":\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"blsKeys\",\"offset\":0,\"slot\":\"419\",\"type\":\"t_mapping(t_bytes_memory_ptr,t_bool)\"},{\"astId\":1022,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"tmKeys\",\"offset\":0,\"slot\":\"420\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1023,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawals\",\"offset\":0,\"slot\":\"421\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1024,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"422\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_address)1025_storage\":{\"encoding\":\"inplace\",\"label\":\"address[255]\",\"numberOfBytes\":\"8160\"},\"t_array(t_address)dyn_storage\":{\"encoding\":\"dynamic_array\",\"label\":\"address[]\",\"numberOfBytes\":\"32\"},\"t_array(t_uint256)1026_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1027_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_bytes_memory_ptr\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_bytes_storage\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct Types.StakerInfo)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_struct(StakerInfo)1028_storage\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_address,t_uint8)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint8)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint8\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_bytes_memory_ptr,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes_memory_ptr\",\"value\":\"t_bool\"},\"t_struct(StakerInfo)1028_storage\":{\"encoding\":\"inplace\",\"label\":\"struct Types.StakerInfo\",\"numberOfBytes\":\"96\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" - -var L1StakingStorageLayout = new(solc.StorageLayout) - -var L1StakingDeployedBin = "0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f14610940578063f2fde38b1461095f578063f4fe7fef1461097e575f80fd5b8063d51c90a9146108a6578063dd4785f5146108bb578063df155033146108fc575f80fd5b8063c7cd469a116100b7578063c7cd469a14610849578063cde4cd1114610868578063d096c3c614610887575f80fd5b8063ab8c53dc146107e9578063ae81de53146107fe578063bfa02ba91461081d575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db914610797578063a3066aab146107ab578063a4f209b0146107ca575f80fd5b8063927ede2d1461070a5780639b19251a1461073d5780639d48f4171461076b575f80fd5b80638a565ac31161016c5780638a565ac3146106935780638da5cb5b146106b25780639168ae72146106dc575f80fd5b80637a9262a2146106155780638142951a14610641578063831cfb5814610660575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610595578063797adbde146105bb5780637a4e87c3146105da575f80fd5b8063692c565b146105335780636f1e853314610562578063715018a614610581575f80fd5b80634d64903a1161022c5780634d64903a146104ea57806352d472eb146104ff5780636801579114610514575f80fd5b806341de239b1461049557806343352d61146104aa57806345bc4d10146104cb575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461043b5780633ccfd60b1461046d5780633ee2a1f914610481575f80fd5b8063320ff860146103bf57806335928991146103de5780633a9bbede146103fd575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613d4e565b61099d565b005b34801561035a575f80fd5b50610312610369366004613db5565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613dd5565b610e5f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031c565b3480156103ca575f80fd5b5061034d6103d9366004613dec565b610e8b565b3480156103e9575f80fd5b5061034d6103f8366004613dd5565b61127a565b348015610408575f80fd5b5061042b610417366004613db5565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610446575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b348015610478575f80fd5b5061034d611341565b34801561048c575f80fd5b5061034d611579565b3480156104a0575f80fd5b5061031260995481565b3480156104b5575f80fd5b506104be61158b565b60405161031c9190613e94565b3480156104d6575f80fd5b506103126104e5366004613dd5565b6115de565b3480156104f5575f80fd5b5061031260985481565b34801561050a575f80fd5b50610312609a5481565b34801561051f575f80fd5b5061042b61052e366004613db5565b61199a565b34801561053e575f80fd5b5061042b61054d366004613dd5565b6101a46020525f908152604090205460ff1681565b34801561056d575f80fd5b5061042b61057c366004613db5565b611a69565b34801561058c575f80fd5b5061034d611b09565b3480156105a0575f80fd5b5061042b6105af366004613f23565b60019695505050505050565b3480156105c6575f80fd5b5061039a6105d5366004613dd5565b611b1a565b3480156105e5575f80fd5b5061042b6105f4366004613fc9565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610620575f80fd5b5061031261062f366004613db5565b6101a56020525f908152604090205481565b34801561064c575f80fd5b5061034d61065b366004614003565b611b50565b34801561066b575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b5061034d6106ad366004613dd5565b61211a565b3480156106bd575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661039a565b3480156106e7575f80fd5b506106fb6106f6366004613db5565b6121d7565b60405161031c939291906140bc565b348015610715575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610748575f80fd5b5061042b610757366004613db5565b609e6020525f908152604090205460ff1681565b348015610776575f80fd5b5061078a610785366004613dd5565b612297565b60405161031c91906140f9565b3480156107a2575f80fd5b5061078a6123ce565b3480156107b6575f80fd5b5061034d6107c5366004613db5565b6125b0565b3480156107d5575f80fd5b5061034d6107e4366004613dd5565b612721565b3480156107f4575f80fd5b50610312609d5481565b348015610809575f80fd5b5061034d610818366004613dd5565b6127eb565b348015610828575f80fd5b5060975461039a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610854575f80fd5b5061034d610863366004614152565b6128a8565b348015610873575f80fd5b5061034d610882366004613db5565b612ac6565b348015610892575f80fd5b506103126108a1366004613db5565b612b41565b3480156108b1575f80fd5b50610312609b5481565b3480156108c6575f80fd5b506108ea6108d5366004613db5565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b348015610907575f80fd5b5061042b610916366004613db5565b73ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b34801561094b575f80fd5b5061031261095a3660046141b9565b612be2565b34801561096a575f80fd5b5061034d610979366004613db5565b612d55565b348015610989575f80fd5b5061034d610998366004613dd5565b612e09565b335f818152609e602052604090205460ff16610a1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a2602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f616c7265616479207265676973746572656400000000000000000000000000006044820152606401610a11565b8215801590610ac557505f8381526101a4602052604090205460ff16155b610b2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b6579000000000000006044820152606401610a11565b8151610100148015610b5e57506101a382604051610b4991906141f8565b9081526040519081900360200190205460ff16155b610bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420626c73207075626b657900000000000000000000000000006044820152606401610a11565b6098543414610c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b6040518060600160405280610c413390565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610cc190826142a8565b50905050610cd4610ccf3390565b612ec6565b60016101a383604051610ce791906141f8565b9081526040805191829003602090810190922080549315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610d643390565b8484604051610d75939291906140bc565b60405180910390a1335f9081526101a260209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff168152600182015492810192909252600281018054610e5a9484019190610dd590614213565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0190614213565b8015610e4c5780601f10610e2357610100808354040283529160200191610e4c565b820191905f5260205f20905b815481529060010190602001808311610e2f57829003601f168201915b505050505081525050613033565b505050565b60a08160ff8110610e6e575f80fd5b015473ffffffffffffffffffffffffffffffffffffffff16905081565b610e93613186565b5f5b815181101561123657610ec0828281518110610eb357610eb36143c4565b602002602001015161199a565b610f4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a11565b6101a55f838381518110610f6257610f626143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20545f1461100c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611019904361441e565b6101a55f84848151811061102f5761102f6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550611096828281518110611089576110896143c4565b6020026020010151613207565b8181815181106110a8576110a86143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f8585815181106110fd576110fd6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205460405161114e91815260200190565b60405180910390a2609e5f83838151811061116b5761116b6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f8484815181106111d2576111d26143c4565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610e95565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b60405180910390a16112778161333a565b50565b611282613186565b5f8111801561129457506101a6548114155b6112fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61134a3361199a565b6113b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f6e6c7920616374697665207374616b657200000000000000000000000000006044820152606401610a11565b335f9081526101a5602052604090205415611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611434904361441e565b335f8181526101a5602052604090209190915561145090613207565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f81518110611510576115106143c4565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b611581613186565b61158961345d565b565b611593613bdf565b60408051611fe08101918290529060a09060ff9082845b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116115aa575050505050905090565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610a11565b61167f6137ae565b5f61168983612297565b90505f805b82518110156118b0575f6101a55f8584815181106116ae576116ae6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541115611765576101a55f84838151811061170c5761170c6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f90556098548261175e919061441e565b91506118a8565b6117ac83828151811061177a5761177a6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b6118a8576098546117bd908361441e565b91506117d4838281518110611089576110896143c4565b609e5f8483815181106117e9576117e96143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f858481518110611850576118506143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b60010161168e565b505f6064609a54836118c29190614431565b6118cc9190614448565b90506118d88183614480565b609d5f8282546118e8919061441e565b90915550506097546119109073ffffffffffffffffffffffffffffffffffffffff1682613821565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161193f91906140f9565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848360405161197691906140f9565b60405180910390a16119878361333a565b925050506119956001606555565b919050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff1681036119d057505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611a089060019060ff16614493565b60ff1660ff8110611a1b57611a1b6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16148015611a63575073ffffffffffffffffffffffffffffffffffffffff82165f9081526101a16020526040902054155b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff168103611a9f57505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611ad79060019060ff16614493565b60ff1660ff8110611aea57611aea6143c4565b015473ffffffffffffffffffffffffffffffffffffffff161492915050565b611b11613186565b6115895f6138f8565b6101a08181548110611b2a575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b5f54610100900460ff1615808015611b6e57505f54600160ff909116105b80611b875750303b158015611b8757505f5460ff166001145b611c13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a11565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611c6f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8816611cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610a11565b5f8711611d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b5f8611611dbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b5f8511611e27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b7300006044820152606401610a11565b5f8311611e90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b6572000000006044820152606401610a11565b5f8211611ef9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b6572736044820152606401610a11565b5f84118015611f09575060648411155b611f94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f74616765000000000000000000000000000000000000000000000000000000006064820152608401610a11565b611f9c61396e565b611fa4613a0c565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015612110575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b612122613186565b5f811180156121335750609c548114155b612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f79101611335565b6101a26020525f908152604090208054600182015460028301805473ffffffffffffffffffffffffffffffffffffffff90931693919261221690614213565b80601f016020809104026020016040519081016040528092919081815260200182805461224290614213565b801561228d5780601f106122645761010080835404028352916020019161228d565b820191905f5260205f20905b81548152906001019060200180831161227057829003601f168201915b5050505050905083565b6060600182901c5f5b81156122c7576122b181600161441e565b90506122be600183614480565b821691506122a0565b8067ffffffffffffffff8111156122e0576122e0613c48565b604051908082528060200260200182016040528015612309578160200160208202803683370190505b5092505f60015b60ff8160ff16116123c557600160ff82161b8616156123b35760a0612336600183614493565b60ff1660ff8110612349576123496143c4565b0154855173ffffffffffffffffffffffffffffffffffffffff90911690869084908110612378576123786143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526123a882600161441e565b9150828210156123c5575b806123bd816144ac565b915050612310565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff8110156124b7575f60a08260ff8110612416576124166143c4565b015473ffffffffffffffffffffffffffffffffffffffff161480159061247857506101a15f60a08360ff811061244e5761244e6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054155b156124af5782612487816144ca565b935050600182828151811061249e5761249e6143c4565b911515602092830291909101909101525b6001016123f9565b505f8267ffffffffffffffff8111156124d2576124d2613c48565b6040519080825280602002602001820160405280156124fb578160200160208202803683370190505b5090505f805b60ff8110156125a65783818151811061251c5761251c6143c4565b60200260200101511561259e5760a08160ff811061253c5761253c6143c4565b0154835173ffffffffffffffffffffffffffffffffffffffff9091169084908490811061256b5761256b6143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528161259a816144ca565b9250505b600101612501565b5090949350505050565b6125b86137ae565b335f9081526101a5602052604090205461262e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7769746864726177616c206e6f742065786973740000000000000000000000006044820152606401610a11565b335f9081526101a560205260409020544310156126a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f7769746864726177616c206c6f636b65640000000000000000000000000000006044820152606401610a11565b335f9081526101a560205260408120556126bf61345d565b6040805173ffffffffffffffffffffffffffffffffffffffff83168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a261271781609854613821565b6112776001606555565b612729613186565b5f81118015612739575060648111155b80156127475750609a548114155b6127ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610a11565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba9101611335565b6127f3613186565b5f811180156128045750609b548114155b61286a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c9101611335565b6128b0613186565b5f5b838110156129fa57609f5f8686848181106128cf576128cf6143c4565b90506020020160208101906128e49190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f205460ff1615612974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e2072656d6f766564206c69737400000000000000000000000000000000006044820152606401610a11565b6001609e5f87878581811061298b5761298b6143c4565b90506020020160208101906129a09190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556001016128b2565b505f5b81811015612a8257609e5f848484818110612a1a57612a1a6143c4565b9050602002016020810190612a2f9190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001016129fd565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac862284848484604051612ab89493929190614553565b60405180910390a150505050565b612ace613186565b612ad66137ae565b609d54612ae38282613821565b5f609d556040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a1506112776001606555565b5f612b4b82611a69565b612bb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b5073ffffffffffffffffffffffffffffffffffffffff165f90815261019f6020526040902054600160ff9091161b90565b5f60ff821115612c4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e6473000000006044820152606401610a11565b5f5b82811015612d4e57612c82848483818110612c6d57612c6d6143c4565b905060200201602081019061057c9190613db5565b612ce8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b61019f5f858584818110612cfe57612cfe6143c4565b9050602002016020810190612d139190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054600160ff90911681901b929092179101612c50565b5092915050565b612d5d613186565b73ffffffffffffffffffffffffffffffffffffffff8116612e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a11565b611277816138f8565b612e11613186565b5f81118015612e2257506098548114155b612e88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de743689101611335565b5f5b60ff8160ff161015612fd0575f60a060ff808416908110612eeb57612eeb6143c4565b015473ffffffffffffffffffffffffffffffffffffffff1603612fc8578160a08260ff1660ff8110612f1f57612f1f6143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055612f6e816001614584565b73ffffffffffffffffffffffffffffffffffffffff929092165f90815261019f6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff9093169290921790915550565b600101612ec8565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f736c6f742066756c6c00000000000000000000000000000000000000000000006044820152606401610a11565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016130a2919061459d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f604051808303815f87803b15801561316d575f80fd5b505af115801561317f573d5f803e3d5ffd5b5050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314611589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a11565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526101a1602052604090205415613294576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f616c726561647920696e2064656c6574654c69737400000000000000000000006044820152606401610a11565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316179055609954613311904361441e565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526101a16020526040902055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016133a991906140f9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f5b6101a05481101561127757436101a15f6101a08481548110613483576134836143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020541161379c5760a0600161019f5f6101a085815481106134d5576134d56143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054613513919060ff16614493565b60ff1660ff8110613526576135266143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110613568576135686143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556101a080546101a2929190849081106135d9576135d96143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560018101829055906136446002830182613bfe565b50506101a15f6101a0838154811061365e5761365e6143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040018120556101a080546136a090600190614480565b815481106136b0576136b06143c4565b5f918252602090912001546101a0805473ffffffffffffffffffffffffffffffffffffffff90921691839081106136e9576136e96143c4565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101a080548061374057613740614626565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905561345f565b806137a6816144ca565b91505061345f565b60026065540361381a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a11565b6002606555565b80156138ed575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461387d576040519150601f19603f3d011682016040523d82523d5f602084013e613882565b606091505b5050905080610e5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610a11565b5050565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16613a04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613aaa565b5f54610100900460ff16613aa2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613b49565b5f54610100900460ff16613b40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589336138f8565b5f54610100900460ff166138f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b60405180611fe0016040528060ff906020820280368337509192915050565b508054613c0a90614213565b5f825580601f10613c19575050565b601f0160209004905f5260205f209081019061127791905b80821115613c44575f8155600101613c31565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613cbc57613cbc613c48565b604052919050565b5f82601f830112613cd3575f80fd5b813567ffffffffffffffff811115613ced57613ced613c48565b613d1e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613c75565b818152846020838601011115613d32575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613d5f575f80fd5b82359150602083013567ffffffffffffffff811115613d7c575f80fd5b613d8885828601613cc4565b9150509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611995575f80fd5b5f60208284031215613dc5575f80fd5b613dce82613d92565b9392505050565b5f60208284031215613de5575f80fd5b5035919050565b5f6020808385031215613dfd575f80fd5b823567ffffffffffffffff80821115613e14575f80fd5b818501915085601f830112613e27575f80fd5b813581811115613e3957613e39613c48565b8060051b9150613e4a848301613c75565b8181529183018401918481019088841115613e63575f80fd5b938501935b83851015613e8857613e7985613d92565b82529385019390850190613e68565b98975050505050505050565b611fe0810181835f5b60ff811015613ed257815173ffffffffffffffffffffffffffffffffffffffff16835260209283019290910190600101613e9d565b50505092915050565b5f8083601f840112613eeb575f80fd5b50813567ffffffffffffffff811115613f02575f80fd5b6020830191508360208260051b8501011115613f1c575f80fd5b9250929050565b5f805f805f8060808789031215613f38575f80fd5b86359550602087013567ffffffffffffffff80821115613f56575f80fd5b613f628a838b01613edb565b9097509550604089013594506060890135915080821115613f81575f80fd5b818901915089601f830112613f94575f80fd5b813581811115613fa2575f80fd5b8a6020828501011115613fb3575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613fd9575f80fd5b813567ffffffffffffffff811115613fef575f80fd5b613ffb84828501613cc4565b949350505050565b5f805f805f805f60e0888a031215614019575f80fd5b61402288613d92565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561406b578181015183820152602001614053565b50505f910152565b5f815180845261408a816020860160208601614051565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6140f06060830184614073565b95945050505050565b602080825282518282018190525f9190848201906040850190845b8181101561414657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614114565b50909695505050505050565b5f805f8060408587031215614165575f80fd5b843567ffffffffffffffff8082111561417c575f80fd5b61418888838901613edb565b909650945060208701359150808211156141a0575f80fd5b506141ad87828801613edb565b95989497509550505050565b5f80602083850312156141ca575f80fd5b823567ffffffffffffffff8111156141e0575f80fd5b6141ec85828601613edb565b90969095509350505050565b5f8251614209818460208701614051565b9190910192915050565b600181811c9082168061422757607f821691505b60208210810361425e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610e5a57805f5260205f20601f840160051c810160208510156142895750805b601f840160051c820191505b8181101561317f575f8155600101614295565b815167ffffffffffffffff8111156142c2576142c2613c48565b6142d6816142d08454614213565b84614264565b602080601f831160018114614328575f84156142f25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556143bc565b5f858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561437457888601518255948401946001909101908401614355565b50858210156143b057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611a6357611a636143f1565b8082028115828204841417611a6357611a636143f1565b5f8261447b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115611a6357611a636143f1565b60ff8281168282160390811115611a6357611a636143f1565b5f60ff821660ff81036144c1576144c16143f1565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036144fa576144fa6143f1565b5060010190565b8183525f60208085019450825f5b858110156145485773ffffffffffffffffffffffffffffffffffffffff61453583613d92565b168752958201959082019060010161450f565b509495945050505050565b604081525f614566604083018688614501565b8281036020840152614579818587614501565b979650505050505050565b60ff8181168382160190811115611a6357611a636143f1565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152613ffb6080840182614073565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201525f6146156080830185614073565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a" - -func init() { - if err := json.Unmarshal([]byte(L1StakingStorageLayoutJSON), L1StakingStorageLayout); err != nil { - panic(err) - } - - layouts["L1Staking"] = L1StakingStorageLayout - deployedBytecodes["L1Staking"] = L1StakingDeployedBin -} diff --git a/bindings/bindings/rollup.go b/bindings/bindings/rollup.go index a3e5d0a88..8b52b5a21 100644 --- a/bindings/bindings/rollup.go +++ b/bindings/bindings/rollup.go @@ -40,17 +40,10 @@ type IRollupBatchDataInput struct { WithdrawalRoot [32]byte } -// IRollupBatchSignatureInput is an auto generated low-level Go binding around an user-defined struct. -type IRollupBatchSignatureInput struct { - SignedSequencersBitmap *big.Int - SequencerSets []byte - Signature []byte -} - // RollupMetaData contains all meta data concerning the Rollup contract. var RollupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a060405234801562000010575f80fd5b506040516200578d3803806200578d83398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b60805161562f6200015e5f395f81816106a20152614408015261562f5ff3fe608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddr\",\"type\":\"address\"}],\"name\":\"SubmitterContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_submitterContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newSubmitter\",\"type\":\"address\"}],\"name\":\"initialize4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"pendingBatchCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"submitterContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60a060405234801562000010575f80fd5b506040516200599d3803806200599d83398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b60805161583f6200015e5f395f81816106ab015261481e015261583f5ff3fe608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610b2c578063f2fde38b14610b4b578063f8fa010f14610b6a578063fb1e8b0414610b89575f80fd5b8063d279c19114610ac4578063d8dc99d214610ae3578063de8b303514610af8578063dff7827e14610b17575f80fd5b8063c5553892116100d8578063c555389214610a5e578063cd4edc6914610a7d578063ce5db8d614610a90578063cf9a674514610aa5575f80fd5b8063b3e0a50914610a01578063b8d0a1b014610a20578063bedb86fb14610a3f575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d14610983578063b31a77d3146109ae578063b3484425146109c3578063b35dac4e146109e2575f80fd5b8063a415d8dc14610921578063a479265d1461094f578063a4f209b014610964575f80fd5b80638f1d3776116101a35780638f1d377614610802578063910129d4146108b257806397fc007c146108e3578063a3c9e94c14610902575f80fd5b806388b1ea09146107a15780638da5cb5b146107ba5780638ef622a8146107d7575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107245780636c578c1d1461074f578063715018a61461076e578063728cdbca14610782575f80fd5b80635f77cf1d1461069a57806361267290146106e657806367caa37a14610705575f80fd5b806341f756da1161027957806341f756da146105df57806357e0af6c146105f25780635c975abb146106115780635ef7a94a14610628575f80fd5b80632b7ac3f3146105745780633b70c18a146105ab5780633e001b66146105ca575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e36600461529d565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046152ca565b610b9e565b005b348015610406575f80fd5b506103f9610415366004615328565b610c70565b348015610425575f80fd5b506103a261043436600461529d565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004615370565b610fb5565b34801561047b575f80fd5b506103f961048a3660046153bf565b6114db565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be36600461529d565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee36600461529d565b61189a565b3480156104fe575f80fd5b506103cc61050d36600461529d565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc61053836600461529d565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc61056336600461529d565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c54610593906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105b6575f80fd5b50609b54610593906001600160a01b031681565b3480156105d5575f80fd5b506103cc60aa5481565b6103f96105ed36600461544d565b6118c8565b3480156105fd575f80fd5b506103f961060c36600461529d565b611b66565b34801561061c575f80fd5b5060655460ff166103a2565b348015610633575f80fd5b5061067161064236600461529d565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106a5575f80fd5b506106cd7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b3480156106f1575f80fd5b506103f961070036600461529d565b611c11565b348015610710575f80fd5b506103f961071f36600461544d565b611dee565b34801561072f575f80fd5b506103cc61073e36600461529d565b60ab6020525f908152604090205481565b34801561075a575f80fd5b506103f96107693660046152ca565b612139565b348015610779575f80fd5b506103f96121f6565b34801561078d575f80fd5b506103f961079c366004615487565b612209565b3480156107ac575f80fd5b5060a6546103a29060ff1681565b3480156107c5575f80fd5b506033546001600160a01b0316610593565b3480156107e2575f80fd5b506103cc6107f13660046152ca565b60ae6020525f908152604090205481565b34801561080d575f80fd5b5061086e61081c36600461529d565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108bd575f80fd5b506103a26108cc36600461529d565b5f90815260a4602052604090206003015460ff1690565b3480156108ee575f80fd5b506103f96108fd3660046152ca565b612512565b34801561090d575f80fd5b50609754610593906001600160a01b031681565b34801561092c575f80fd5b506103a261093b3660046152ca565b609f6020525f908152604090205460ff1681565b34801561095a575f80fd5b506103cc60995481565b34801561096f575f80fd5b506103f961097e36600461529d565b6125f5565b34801561098e575f80fd5b506103cc61099d3660046152ca565b60a56020525f908152604090205481565b3480156109b9575f80fd5b506103cc60a85481565b3480156109ce575f80fd5b506103f96109dd3660046154e2565b6126a5565b3480156109ed575f80fd5b506103f96109fc3660046152ca565b6129b2565b348015610a0c575f80fd5b506103f9610a1b366004615370565b612a0b565b348015610a2b575f80fd5b506103f9610a3a3660046154e2565b612d9c565b348015610a4a575f80fd5b506103f9610a59366004615556565b612e25565b348015610a69575f80fd5b506103f9610a7836600461529d565b612f63565b6103f9610a8b366004615588565b613006565b348015610a9b575f80fd5b506103cc60985481565b348015610ab0575f80fd5b506103f9610abf36600461529d565b613598565b348015610acf575f80fd5b506103f9610ade3660046152ca565b61370f565b348015610aee575f80fd5b506103cc60ac5481565b348015610b03575f80fd5b506103a2610b1236600461529d565b6137ce565b348015610b22575f80fd5b506103cc609a5481565b348015610b37575f80fd5b506103f9610b4636600461529d565b613818565b348015610b56575f80fd5b506103f9610b653660046152ca565b6138bb565b348015610b75575f80fd5b506103f9610b843660046152ca565b613948565b348015610b94575f80fd5b506103cc60a95481565b610ba6613e4d565b6001600160a01b0381165f908152609f602052604090205460ff1615610c135760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c78613e4d565b5f8111610cc75760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c0a565b5f80610cd38585613ea7565b915091505f610ce6836001015160c01c90565b5f81815260a160205260409020549091508214610d455760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f60a181610d5387856155dd565b81526020019081526020015f205414610dd35760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b609d548111610e4a5760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b610e556001826155f0565b609e555b8315610fad57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610e9381613f4f565b5f81815260a16020526040812055610eaa816137ce565b15610f05575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ef59084906155dd565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f65575060a85481145b15610f6f575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e59575b505050505050565b60a854156110055760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b61100d614002565b5f806110198484613ea7565b915091505f61102c836001015160c01c90565b5f81815260a16020526040902054909150821461108b5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6110948161189a565b6110e05760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b6110e9816137ce565b156111365760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a4602052604090206003015460ff16156111975760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c0a565b5f81815260a260205260409020600101544210156111f75760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c0a565b605983015160a05f61120a6001856155f0565b81526020019081526020015f2054146112655760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f81815260a06020526040902054156112c05760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c0a565b80609d54600101146113145760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b609d819055600160a35f611329866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561137861136b846011015160c01c90565b600985015160c01c614055565b61138181613f4f565b60a25f61138f6001846155f0565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113eb90846155f0565b81526020019081526020015f205f905560ad5f60018361140b91906155f0565b81526020019081526020015f205f905560a45f60018361142b91906155f0565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d6114b7866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a8541561152b5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611533614002565b60ac54609e545f90815260a260205260408120549091429161155591906155dd565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d19190615603565b6115db91906155dd565b109050811580156115e95750805b15611650575f6115ff6080890160608a0161561a565b61ffff16116116505760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b81806116595750805b6116a55760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c0a565b5f6116bb6116b660208a018a61563b565b613ea7565b5090505f6116cd826001015160c01c90565b6116d89060016155dd565b5f81815260ad60205260408120549192509015611778575f49156117645760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c0a565b505f81815260ad6020526040902054611793565b61179061178860208c018c61569c565b60ff16614112565b90505b61179e8a5f8361424d565b5f806117aa8b8b613ea7565b915091505f6117bd836001015160c01c90565b905080609e54146118105760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461186c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f81815260a2602052604090204260019091015561188b838b8b6147af565b50505050505050505050505050565b5f81815260a26020526040812054158015906118c257505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611934573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195891906156bc565b6119a45760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a854156119f45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6119fc614002565b5f49611a4a5760405162461bcd60e51b815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aae573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad29190615603565b611adc91906155dd565b1015611b44575f611af3608083016060840161561a565b61ffff1611611b445760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b5f611b55611788602084018461569c565b9050611b6282338361424d565b5050565b611b6e613e4d565b5f81118015611b7f57506099548114155b611bcb5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c0a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c3157505f5460ff8083169116105b611ca35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055611cbe613e4d565b5f5460ff1660ff16600214611d155760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c0a565b81611d885760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c0a565b609e545f90815260ab6020526040902054611db157609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7e91906156bc565b611eca5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a85415611f1a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611f22614002565b5f4915611f715760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c0a565b5f611f826116b6602084018461563b565b5090505f611f94826001015160c01c90565b611f9f9060016155dd565b5f81815260ad60205260409020549091506120225760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015612086573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120aa9190615603565b6120b491906155dd565b101561211c575f6120cb608085016060860161561a565b61ffff161161211c5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b61213483335f84815260ad602052604090205461424d565b505050565b612141613e4d565b6001600160a01b0381165f908152609f602052604090205460ff166121a85760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c0a565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c65565b6121fe613e4d565b6122075f614962565b565b5f54610100900460ff161580801561222757505f54600160ff909116105b806122405750303b15801561224057505f5460ff166001145b6122b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805460ff1916600117905580156122d3575f805461ff0019166101001790555b6001600160a01b03861615806122f057506001600160a01b038516155b15612327576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871661237d5760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c0a565b6123856149cb565b61238d614a4f565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612509575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61251a613e4d565b6001600160a01b038116158015906125405750609c546001600160a01b03828116911614155b61258c5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c0a565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6125fd613e4d565b5f8111801561260d575060648111155b801561261b575060a9548114155b6126675760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c0a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c05565b60a854156126f55760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6126fd614002565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612769573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278d91906156bc565b6127d95760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b5f806127e58686613ea7565b915091505f6127f8836001015160c01c90565b5f81815260a1602052604090205490915082146128575760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b612860816137ce565b6128ac5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916128e8916155dd565b11612967575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526129629183916001600160a01b031690614ad3565b612509565b6129728386866147af565b61250981336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614c32565b6129ba613e4d565b60aa80545f9091556129cc8282614cfe565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c05565b612a13613e4d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612a8a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c0a565b5f80612a968484613ea7565b915091505f612aa9836001015160c01c90565b90508015612af95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c0a565b5f612b05846079015190565b905080612b545760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c0a565b600984015160c01c15612ba95760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c0a565b5f612bb5856019015190565b03612c025760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c0a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c2e856039015190565b14612c7b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c0a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612da88686613ea7565b915091505f612dbb836001015160c01c90565b5f81815260a160205260409020549091508214612e1a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6125098386866147af565b612e2d613e4d565b8015612f3157612e3b614da3565b60a65460ff1615612ef05760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612e8f9084906155dd565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f39614dfd565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f13565b50565b612f6b613e4d565b5f81118015612f7c575060ac548114155b612fc85760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c0a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c05565b335f908152609f602052604090205460ff166130645760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c0a565b60a854156130b45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6130bc614002565b60a65460ff161561310f5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c0a565b8167ffffffffffffffff16609d541061316a5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a1602052604090205481146131d15760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6131e48267ffffffffffffffff1661189a565b6132305760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132ab5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a26020526040902060010154421061333b5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c0a565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190615603565b3410156133fe5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161351691815260200190565b60405180910390a35f609d54600161352e91906155dd565b90505b609e548111613586578267ffffffffffffffff168114613574576099545f82815260a260205260408120600101805490919061356e9084906155dd565b90915550505b8061357e816156d7565b915050613531565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135b857505f5460ff8083169116105b61362a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055613645613e4d565b815f036136945760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c0a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b335f90815260a560205260408120549081900361376e5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c0a565b335f90815260a560205260408120556137878282614cfe565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137c291815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118c25750505f90815260a46020526040902060030154610100900460ff161590565b613820613e4d565b5f8111801561383157506098548114155b61387d5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c0a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c05565b6138c3613e4d565b6001600160a01b03811661393f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c0a565b612f6081614962565b5f54600490610100900460ff1615801561396857505f5460ff8083169116105b6139da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff8316176101001790556139f5613e4d565b6001600160a01b03821615801590613a1657505f826001600160a01b03163b115b613a625760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c0a565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90613ac6908490614e36565b905060a081901c15613b1a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610c0a565b6040515f602482018190528291613bab908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052614e36565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f90613c12908790614e36565b90506001600160a01b0383163014613c6c5760405162461bcd60e51b815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610c0a565b81158015613c7957505f81115b613cc55760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610c0a565b609d54609e5414613d185760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c0a565b60a85415613d685760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560975490516001600160a01b03898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861617905550505f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6033546001600160a01b031633146122075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c0a565b5f805f613eb48585614ebf565b90505f8160ff165f03613ed557613ecb8686614f2f565b9094509050613f41565b8160ff1660011480613eea57508160ff166002145b15613ef957613ecb8686614f98565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c0a565b808420925050509250929050565b5f81815260a260205260409020600301546001600160a01b031680613f72575050565b6001600160a01b0381165f90815260ae602052604090205480613fd75760405162461bcd60e51b815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610c0a565b613fe26001826155f0565b6001600160a01b039092165f90815260ae60205260409020919091555050565b60655460ff16156122075760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c0a565b805f03614060575050565b8082035f5b8281101561410c5761010081840381111561407f57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b1580156140e2575f80fd5b505af11580156140f4573d5f803e3d5ffd5b50505050610100830192505061010081019050614065565b50505050565b5f816002036141a1575f6040515f5b80498061412e575061413d565b60208202830152600101614121565b60208102808320920160405290925090508061419b5760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c0a565b50919050565b600149156142175760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c0a565b5f4915614225575f496118c2565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261425c602085018561569c565b60ff1611156142ad5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c0a565b60808301356142fe5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c0a565b60a083013561434f5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c0a565b5f806143616116b6602087018761563b565b915091505f614374836001015160c01c90565b90505f60a1816143858460016155dd565b81526020019081526020015f2054146143e05760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c0a565b609e5481146144315760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461448d5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c0a565b5f81815260ab60205260409020546080870135146144ed5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f6144fc846011015160c01c90565b90505f61452861451260608a0160408b0161570e565b61452260808b0160608c0161561a565b84614feb565b905061453a6080890160608a0161561a565b60019384019361ffff91909116929092019160f99061455c60208b018b61569c565b60ff161061456957506101015b60408051828101909152955061458e8661458660208c018c61569c565b60ff1661502f565b60c084901b60018701526145bc866145ac60808c0160608d0161561a565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161460c60208b018b61569c565b60ff161061463e5761463e8661462860608c0160408d0161570e565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156146a75760a7545f90815260a46020526040902060020154609954429161469a916155dd565b6146a491906155f0565b90505b604051806080016040528042815260200182609854426146c791906155dd565b6146d191906155dd565b81526020016146e660608d0160408e0161570e565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561476589615036565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b806147fc5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c0a565b5f61480b846001015160c01c90565b90505f614819856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614848876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a84861490a885160f81c90565b858888866040518663ffffffff1660e01b815260040161492e959493929190615727565b5f6040518083038186803b158015614944575f80fd5b505afa158015614956573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16614a475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b612207615075565b5f54610100900460ff16614acb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6122076150fd565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614b5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b7e9190615603565b5f86815260a46020526040902060010154909150614b9d9082906155dd565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a590915281208054909190614bdc9084906155dd565b9091555050604051614bef90849061578a565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614c5690846157b6565b614c6091906157cd565b9050614c6c81836155f0565b60aa5f828254614c7c91906155dd565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614ca89084906155dd565b9091555050604051614cbb90849061578a565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611b62575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614d4d576040519150601f19603f3d011682016040523d82523d5f602084013e614d52565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c0a565b614dab614002565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614de03390565b6040516001600160a01b03909116815260200160405180910390a1565b614e05615182565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614de0565b5f805f805f855160208701885afa91503d905060208114821615614e5e5760205f803e5f5192505b818015614e6b5750806020145b614eb75760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610c0a565b505092915050565b5f81614f0d5760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c0a565b82825f818110614f1f57614f1f615805565b919091013560f81c949350505050565b5f8160f9811015614f825760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c0a565b6040519150808483378082016040529250929050565b5f816101018114614f825760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c0a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f9181016150208161ffff8716866151d4565b82900390912095945050505050565b8082535050565b6001600160a01b03811615612f60576001600160a01b0381165f90815260ae6020526040812080546001929061506d9084906155dd565b909155505050565b5f54610100900460ff166150f15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6065805460ff19169055565b5f54610100900460ff166151795760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b61220733614962565b60655460ff166122075760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c0a565b5f825f036151e3575082615296565b609b546001600160a01b03165f5b84811015615290576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015615257573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061527b9190615603565b875250602090950194600193840193016151f1565b50849150505b9392505050565b5f602082840312156152ad575f80fd5b5035919050565b80356001600160a01b0381168114614248575f80fd5b5f602082840312156152da575f80fd5b615296826152b4565b5f8083601f8401126152f3575f80fd5b50813567ffffffffffffffff81111561530a575f80fd5b602083019150836020828501011115615321575f80fd5b9250929050565b5f805f6040848603121561533a575f80fd5b833567ffffffffffffffff811115615350575f80fd5b61535c868287016152e3565b909790965060209590950135949350505050565b5f8060208385031215615381575f80fd5b823567ffffffffffffffff811115615397575f80fd5b6153a3858286016152e3565b90969095509350505050565b5f60e0828403121561419b575f80fd5b5f805f805f606086880312156153d3575f80fd5b853567ffffffffffffffff808211156153ea575f80fd5b6153f689838a016153af565b9650602088013591508082111561540b575f80fd5b61541789838a016152e3565b9096509450604088013591508082111561542f575f80fd5b5061543c888289016152e3565b969995985093965092949392505050565b5f6020828403121561545d575f80fd5b813567ffffffffffffffff811115615473575f80fd5b61547f848285016153af565b949350505050565b5f805f805f8060c0878903121561549c575f80fd5b6154a5876152b4565b95506154b3602088016152b4565b94506154c1604088016152b4565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156154f5575f80fd5b843567ffffffffffffffff8082111561550c575f80fd5b615518888389016152e3565b90965094506020870135915080821115615530575f80fd5b5061553d878288016152e3565b95989497509550505050565b8015158114612f60575f80fd5b5f60208284031215615566575f80fd5b813561529681615549565b803567ffffffffffffffff81168114614248575f80fd5b5f8060408385031215615599575f80fd5b6155a283615571565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118c2576118c26155b0565b818103818111156118c2576118c26155b0565b5f60208284031215615613575f80fd5b5051919050565b5f6020828403121561562a575f80fd5b813561ffff81168114615296575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261566e575f80fd5b83018035915067ffffffffffffffff821115615688575f80fd5b602001915036819003821315615321575f80fd5b5f602082840312156156ac575f80fd5b813560ff81168114615296575f80fd5b5f602082840312156156cc575f80fd5b815161529681615549565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615707576157076155b0565b5060010190565b5f6020828403121561571e575f80fd5b61529682615571565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156157a9576020818601810151858301520161578f565b505f920191825250919050565b80820281158282048414176118c2576118c26155b0565b5f82615800577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a", } // RollupABI is the input ABI used to generate the binding from. @@ -408,21 +401,21 @@ func (_Rollup *RollupCallerSession) BatchChallengedSuccess(batchIndex *big.Int) // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { var out []interface{} err := _Rollup.contract.Call(opts, &out, "batchDataStore", batchIndex) outstruct := new(struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }) if err != nil { return *outstruct, err @@ -431,7 +424,7 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big outstruct.OriginTimestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.FinalizeTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) outstruct.BlockNumber = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.SignedSequencersBitmap = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Submitter = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) return *outstruct, err @@ -439,24 +432,24 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupCallerSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } @@ -836,37 +829,6 @@ func (_Rollup *RollupCallerSession) IsChallenger(challengerAddress common.Addres return _Rollup.Contract.IsChallenger(&_Rollup.CallOpts, challengerAddress) } -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupCaller) L1StakingContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Rollup.contract.Call(opts, &out, "l1StakingContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupSession) L1StakingContract() (common.Address, error) { - return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) -} - -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupCallerSession) L1StakingContract() (common.Address, error) { - return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) -} - // LastCommittedBatchIndex is a free data retrieval call binding the contract method 0x121dcd50. // // Solidity: function lastCommittedBatchIndex() view returns(uint256) @@ -1022,6 +984,37 @@ func (_Rollup *RollupCallerSession) Paused() (bool, error) { return _Rollup.Contract.Paused(&_Rollup.CallOpts) } +// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. +// +// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) +func (_Rollup *RollupCaller) PendingBatchCount(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { + var out []interface{} + err := _Rollup.contract.Call(opts, &out, "pendingBatchCount", submitter) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. +// +// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) +func (_Rollup *RollupSession) PendingBatchCount(submitter common.Address) (*big.Int, error) { + return _Rollup.Contract.PendingBatchCount(&_Rollup.CallOpts, submitter) +} + +// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. +// +// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) +func (_Rollup *RollupCallerSession) PendingBatchCount(submitter common.Address) (*big.Int, error) { + return _Rollup.Contract.PendingBatchCount(&_Rollup.CallOpts, submitter) +} + // ProofRewardPercent is a free data retrieval call binding the contract method 0xfb1e8b04. // // Solidity: function proofRewardPercent() view returns(uint256) @@ -1206,6 +1199,37 @@ func (_Rollup *RollupCallerSession) RollupDelayPeriod() (*big.Int, error) { return _Rollup.Contract.RollupDelayPeriod(&_Rollup.CallOpts) } +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupCaller) SubmitterContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Rollup.contract.Call(opts, &out, "submitterContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupSession) SubmitterContract() (common.Address, error) { + return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) +} + +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupCallerSession) SubmitterContract() (common.Address, error) { + return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) +} + // Verifier is a free data retrieval call binding the contract method 0x2b7ac3f3. // // Solidity: function verifier() view returns(address) @@ -1352,67 +1376,67 @@ func (_Rollup *RollupTransactorSession) ClaimReward(receiver common.Address) (*t return _Rollup.Contract.ClaimReward(&_Rollup.TransactOpts, receiver) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitState", batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitState", batchDataInput) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) } // FinalizeBatch is a paid mutator transaction binding the contract method 0x13361101. @@ -1459,23 +1483,23 @@ func (_Rollup *RollupTransactorSession) ImportGenesisBatch(_batchHeader []byte) // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "initialize", _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize", _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactorSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactorSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize2 is a paid mutator transaction binding the contract method 0x61267290. @@ -1520,6 +1544,27 @@ func (_Rollup *RollupTransactorSession) Initialize3(_rollupDelayPeriod *big.Int) return _Rollup.Contract.Initialize3(&_Rollup.TransactOpts, _rollupDelayPeriod) } +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupTransactor) Initialize4(opts *bind.TransactOpts, _newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize4", _newSubmitter) +} + +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +} + +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupTransactorSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +} + // ProveState is a paid mutator transaction binding the contract method 0xb3484425. // // Solidity: function proveState(bytes _batchHeader, bytes _batchProof) returns() @@ -3250,6 +3295,159 @@ func (_Rollup *RollupFilterer) ParseRevertBatch(log types.Log) (*RollupRevertBat return event, nil } +// RollupSubmitterContractUpdatedIterator is returned from FilterSubmitterContractUpdated and is used to iterate over the raw logs and unpacked data for SubmitterContractUpdated events raised by the Rollup contract. +type RollupSubmitterContractUpdatedIterator struct { + Event *RollupSubmitterContractUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *RollupSubmitterContractUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(RollupSubmitterContractUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(RollupSubmitterContractUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *RollupSubmitterContractUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *RollupSubmitterContractUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// RollupSubmitterContractUpdated represents a SubmitterContractUpdated event raised by the Rollup contract. +type RollupSubmitterContractUpdated struct { + OldAddr common.Address + NewAddr common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterContractUpdated is a free log retrieval operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterOpts, oldAddr []common.Address, newAddr []common.Address) (*RollupSubmitterContractUpdatedIterator, error) { + + var oldAddrRule []interface{} + for _, oldAddrItem := range oldAddr { + oldAddrRule = append(oldAddrRule, oldAddrItem) + } + var newAddrRule []interface{} + for _, newAddrItem := range newAddr { + newAddrRule = append(newAddrRule, newAddrItem) + } + + logs, sub, err := _Rollup.contract.FilterLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + if err != nil { + return nil, err + } + return &RollupSubmitterContractUpdatedIterator{contract: _Rollup.contract, event: "SubmitterContractUpdated", logs: logs, sub: sub}, nil +} + +// WatchSubmitterContractUpdated is a free log subscription operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpts, sink chan<- *RollupSubmitterContractUpdated, oldAddr []common.Address, newAddr []common.Address) (event.Subscription, error) { + + var oldAddrRule []interface{} + for _, oldAddrItem := range oldAddr { + oldAddrRule = append(oldAddrRule, oldAddrItem) + } + var newAddrRule []interface{} + for _, newAddrItem := range newAddr { + newAddrRule = append(newAddrRule, newAddrItem) + } + + logs, sub, err := _Rollup.contract.WatchLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(RollupSubmitterContractUpdated) + if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterContractUpdated is a log parse operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) ParseSubmitterContractUpdated(log types.Log) (*RollupSubmitterContractUpdated, error) { + event := new(RollupSubmitterContractUpdated) + if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // RollupUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the Rollup contract. type RollupUnpausedIterator struct { Event *RollupUnpaused // Event containing the contract specifics and raw log diff --git a/bindings/bindings/rollup_more.go b/bindings/bindings/rollup_more.go index a78f509fd..e0a97d7fc 100644 --- a/bindings/bindings/rollup_more.go +++ b/bindings/bindings/rollup_more.go @@ -9,11 +9,11 @@ import ( "morph-l2/bindings/solc" ) -const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"l1StakingContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1030_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1032_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1033_storage\"},\"t_struct(BatchChallenge)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" +const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1032_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"submitterContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1030,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"pendingBatchCount\",\"offset\":0,\"slot\":\"174\",\"type\":\"t_mapping(t_address,t_uint256)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1033_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1034_storage\"},\"t_struct(BatchChallenge)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1034_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" var RollupStorageLayout = new(solc.StorageLayout) -var RollupDeployedBin = "0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610b1f578063e3fff1dd14610b34578063f2fde38b14610b53578063fb1e8b0414610b72575f80fd5b8063d8dc99d214610abf578063ddd8a3dc14610ad4578063de8b303514610b00575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a59578063ce5db8d614610a6c578063cf9a674514610a81578063d279c19114610aa0575f80fd5b8063b8d0a1b0146109fc578063bedb86fb14610a1b578063c555389214610a3a575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461098a578063b34844251461099f578063b35dac4e146109be578063b3e0a509146109dd575f80fd5b8063a479265d1461092b578063a4f209b014610940578063abc8d68d1461095f575f80fd5b80638f1d3776116101985780638f1d3776146107e3578063910129d4146108ad57806397fc007c146108de578063a415d8dc146108fd575f80fd5b8063728cdbca1461078157806388b1ea09146107a05780638da5cb5b146107b9575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e578063612672901461070457806368589dfa146107235780636c578c1d1461074e578063715018a61461076d575f80fd5b80635c975abb146106415780635ef7a94a146106585780635f77cf1d146106b8575f80fd5b80633e001b661161026e5780633e001b66146105db578063428868b5146105f05780634e8f1d671461060357806357e0af6c14610622575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a146105af575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004615c9f565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004615cd9565b610b87565b005b3480156103f0575f80fd5b506103e36103ff366004615d37565b610cab565b34801561040f575f80fd5b5061038c61041e366004615c9f565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004615d7f565b611097565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004615c9f565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004615dde565b6116b6565b3480156104c9575f80fd5b5061038c6104d8366004615c9f565b611b64565b3480156104e8575f80fd5b506103b66104f7366004615c9f565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004615c9f565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004615c9f565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610398565b3480156105ba575f80fd5b50609b5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105e6575f80fd5b506103b660aa5481565b6103e36105fe366004615dde565b611b92565b34801561060e575f80fd5b506103e361061d366004615e3e565b611fd6565b34801561062d575f80fd5b506103e361063c366004615c9f565b612440565b34801561064c575f80fd5b5060655460ff1661038c565b348015610663575f80fd5b50610698610672366004615c9f565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b3480156106c3575f80fd5b506106eb7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b34801561070f575f80fd5b506103e361071e366004615c9f565b612505565b34801561072e575f80fd5b506103b661073d366004615c9f565b60ab6020525f908152604090205481565b348015610759575f80fd5b506103e3610768366004615cd9565b612768565b348015610778575f80fd5b506103e3612877565b34801561078c575f80fd5b506103e361079b366004615eef565b61288a565b3480156107ab575f80fd5b5060a65461038c9060ff1681565b3480156107c4575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661058a565b3480156107ee575f80fd5b5061085c6107fd366004615c9f565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b3480156108b8575f80fd5b5061038c6108c7366004615c9f565b5f90815260a4602052604090206003015460ff1690565b3480156108e9575f80fd5b506103e36108f8366004615cd9565b612c53565b348015610908575f80fd5b5061038c610917366004615cd9565b609f6020525f908152604090205460ff1681565b348015610936575f80fd5b506103b660995481565b34801561094b575f80fd5b506103e361095a366004615c9f565b612d77565b34801561096a575f80fd5b506103b6610979366004615cd9565b60a56020525f908152604090205481565b348015610995575f80fd5b506103b660a85481565b3480156109aa575f80fd5b506103e36109b9366004615f4a565b612e41565b3480156109c9575f80fd5b506103e36109d8366004615cd9565b613220565b3480156109e8575f80fd5b506103e36109f7366004615d7f565b613286565b348015610a07575f80fd5b506103e3610a16366004615f4a565b61367f565b348015610a26575f80fd5b506103e3610a35366004615fbe565b613722565b348015610a45575f80fd5b506103e3610a54366004615c9f565b6138b5565b6103e3610a67366004615ff0565b613972565b348015610a77575f80fd5b506103b660985481565b348015610a8c575f80fd5b506103e3610a9b366004615c9f565b614087565b348015610aab575f80fd5b506103e3610aba366004615cd9565b614264565b348015610aca575f80fd5b506103b660ac5481565b348015610adf575f80fd5b5060975461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b0b575f80fd5b5061038c610b1a366004615c9f565b61434a565b348015610b2a575f80fd5b506103b6609a5481565b348015610b3f575f80fd5b506103e3610b4e366004615c9f565b6143a1565b348015610b5e575f80fd5b506103e3610b6d366004615cd9565b61445e565b348015610b7d575f80fd5b506103b660a95481565b610b8f614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610c23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610cb3614512565b5f8111610d1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c1a565b5f80610d288585614593565b915091505f610d3b836001015160c01c90565b5f81815260a160205260409020549091508214610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f60a181610dc28785616045565b81526020019081526020015f205414610e5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b609d548111610eed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b610ef8600182616058565b609e555b831561108f57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610f448161434a565b15610fca575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091610f9c908490616045565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a85415801590611047575060a85481145b15611051575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610efc575b505050505050565b60a85415611101576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611109614655565b5f806111158484614593565b915091505f611128836001015160c01c90565b5f81815260a1602052604090205490915082146111a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6111aa81611b64565b611210576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b6112198161434a565b15611280576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003015460ff16156112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c1a565b5f81815260a26020526040902060010154421015611375576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c1a565b605983015160a05f611388600185616058565b81526020019081526020015f2054146113fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f81815260a0602052604090205415611472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c1a565b80609d54600101146114e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b609d819055600160a35f6114f5866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a06020526040902055611562611555846011015160c01c90565b600985015160c01c6146c2565b60a25f611570600184616058565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab91906115a99084616058565b81526020019081526020015f205f905560ad5f6001836115c99190616058565b81526020019081526020015f205f905560a45f6001836115e99190616058565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611692866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa15801561173c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611760919061606b565b6117c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611838614655565b5f49156118a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c1a565b5f6118b76118b26020850185616086565b614593565b5090505f6118c9826001015160c01c90565b6118d4906001616045565b5f81815260ad6020526040902054909150611971576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa1580156119e2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a0691906160e7565b611a109190616045565b1015611a92575f611a2760808601606087016160fe565b61ffff1611611a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b3e91906160e7565b9050611b5d85858360ad5f8781526020019081526020015f205461478c565b5050505050565b5f81815260a2602052604081205415801590611b8c57505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611c18573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c3c919061606b565b611ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611d14614655565b5f611d256118b26020850185616086565b5090505f611d37826001015160c01c90565b611d42906001616045565b5f81815260ad602052604090205490915015611de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7591906160e7565b611e7f9190616045565b1015611f01575f611e9660808601606087016160fe565b61ffff1611611f01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611f89573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fad91906160e7565b90505f611fc8611fc0602088018861611f565b60ff16614ec9565b905061108f8686848461478c565b60a85415612040576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612048614655565b60ac54609e545f90815260a260205260408120549091429161206a9190616045565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120dc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210091906160e7565b61210a9190616045565b109050811580156121185750805b15612199575f61212e60808a0160608b016160fe565b61ffff1611612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b81806121a25750805b612208576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c1a565b5f6122196118b260208b018b616086565b5090505f61222b826001015160c01c90565b612236906001616045565b5f81815260ad602052604081205491925090156122f0575f49156122dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c1a565b505f81815260ad6020526040902054612303565b612300611fc060208d018d61611f565b90505b61230f8b8b5f8461478c565b5f8061231b8b8b614593565b915091505f61232e836001015160c01c90565b905080609e541461239b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214612411576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f81815260a26020526040902042600190910155612430838b8b615038565b5050505050505050505050505050565b612448614512565b5f8111801561245957506099548114155b6124bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c1a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561252557505f5460ff8083169116105b6125b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556125ec5f5460ff1690565b60ff16600214612658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c1a565b816126e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c1a565b609e545f90815260ab602052604090205461270e57609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b612770614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff166127fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c1a565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610ca0565b61287f614512565b6128885f615212565b565b5f54610100900460ff16158080156128a857505f54600160ff909116105b806128c15750303b1580156128c157505f5460ff166001145b61294d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156129a9575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806129e0575073ffffffffffffffffffffffffffffffffffffffff8516155b15612a17576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8716612a94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610c1a565b612a9c615288565b612aa4615326565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612c4a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612c5b614512565b73ffffffffffffffffffffffffffffffffffffffff811615801590612c9b5750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612d01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c1a565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612d7f614512565b5f81118015612d8f575060648111155b8015612d9d575060a9548114155b612e03576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c1a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b022391016124f9565b60a85415612eab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612eb3614655565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612f39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5d919061606b565b612fc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b5f80612fcf8686614593565b915091505f612fe2836001015160c01c90565b5f81815260a16020526040902054909150821461305b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6130648161434a565b6130ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161314191616045565b116131d5575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526131d0918391906153c4565b612c4a565b6131e0838686615038565b612c4a81336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615547565b613228614512565b60aa80545f90915561323a828261562d565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d8791016124f9565b61328e614512565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea541561331f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c1a565b5f8061332b8484614593565b915091505f61333e836001015160c01c90565b905080156133a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c1a565b5f6133b4846079015190565b90508061341d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c1a565b600984015160c01c1561348c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c1a565b5f613498856019015190565b036134ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c1a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461352b856039015190565b14613592576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c1a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061368b8686614593565b915091505f61369e836001015160c01c90565b5f81815260a160205260409020549091508214613717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b612c4a838686615038565b61372a614512565b8015613883576137386156ff565b60a65460ff16156138355760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091613799908490616045565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b61388b615784565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613858565b50565b6138bd614512565b5f811180156138ce575060ac548114155b613934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c1a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad191016124f9565b335f908152609f602052604090205460ff166139ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c1a565b60a85415613a54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b613a5c614655565b60a65460ff1615613ac9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c1a565b8167ffffffffffffffff16609d5410613b3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a160205260409020548114613bbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b613bd28267ffffffffffffffff16611b64565b613c38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613cda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a260205260409020600101544210613d84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c1a565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dee573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1291906160e7565b341015613e7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613fe791815260200190565b60405180910390a35f609d546001613fff9190616045565b90505b609e548111614057578267ffffffffffffffff168114614045576099545f82815260a260205260408120600101805490919061403f908490616045565b90915550505b8061404f8161613f565b915050614002565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff161580156140a757505f5460ff8083169116105b614133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001781558290036141cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c1a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b335f90815260a56020526040812054908190036142dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c1a565b335f90815260a560205260408120556142f6828261562d565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161433e91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611b8c5750505f90815260a46020526040902060030154610100900460ff161590565b6143a9614512565b5f811180156143ba57506098548114155b614420576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c1a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a43791016124f9565b614466614512565b73ffffffffffffffffffffffffffffffffffffffff8116614509576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c1a565b6138b281615212565b60335473ffffffffffffffffffffffffffffffffffffffff163314612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c1a565b5f805f6145a085856157db565b90505f8160ff165f036145c1576145b78686615865565b9094509050614647565b8160ff16600114806145d657508160ff166002145b156145e5576145b786866158e8565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c1a565b808420925050509250929050565b60655460ff1615612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c1a565b805f036146cd575050565b8082035f5b82811015614786576101008184038111156146ec57508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b15801561475c575f80fd5b505af115801561476e573d5f803e3d5ffd5b505050506101008301925050610100810190506146d2565b50505050565b600261479b602086018661611f565b60ff161115614806576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c1a565b6080840135614871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c1a565b60a08401356148dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c1a565b5f806148ee6118b26020880188616086565b915091505f614901836001015160c01c90565b90505f60a181614912846001616045565b81526020019081526020015f205414614987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c1a565b609e5481146149f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214614a68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c1a565b5f81815260ab6020526040902054608088013514614ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f614af1846011015160c01c90565b90505f614b1d614b0760608b0160408c01616176565b614b1760808c0160608d016160fe565b84615955565b9050614b2f60808a0160608b016160fe565b60019384019361ffff91909116929092019160f990614b5160208c018c61611f565b60ff1610614b5e57506101015b604080518281019091529550614b8386614b7b60208d018d61611f565b60ff16615999565b60c084901b6001870152614bb186614ba160808d0160608e016160fe565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152614c1586614bf660208c018c616086565b604051614c0492919061618f565b604051809103902060b99190910152565b60d986018590526001614c2b60208c018c61611f565b60ff1610614c5d57614c5d86614c4760608d0160408e01616176565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff1615614cc65760a7545f90815260a460205260409020600201546099544291614cb991616045565b614cc39190616058565b90505b60405180608001604052804281526020018260985442614ce69190616045565b614cf09190616045565b8152602001614d0560608e0160408f01616176565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e86905560975473ffffffffffffffffffffffffffffffffffffffff1692506374fe27b791508a3590614d8c90614d86908d018d616086565b5f6159a0565b5f614d9a60408e018e616086565b6040518663ffffffff1660e01b8152600401614dba9594939291906161e5565b602060405180830381865afa158015614dd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df9919061606b565b614e85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f81600203614f72575f6040515f5b804980614ee55750614ef4565b60208202830152600101614ed8565b602081028083209201604052909250905080614f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c1a565b50919050565b60014915615002576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f4915615010575f49611b8c565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b8061509f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c1a565b5f6150ae846001015160c01c90565b90505f6150bc856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006150eb876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a8486151ba885160f81c90565b858888866040518663ffffffff1660e01b81526004016151de959493929190616265565b5f6040518083038186803b1580156151f4575f80fd5b505afa158015615206573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff1661531e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b6128886159f4565b5f54610100900460ff166153bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b612888615ab4565b60a88390555f83815260a460205260408082205460975491517f45bc4d10000000000000000000000000000000000000000000000000000000008152600481018690526801000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116939216906345bc4d10906024016020604051808303815f875af1158015615455573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061547991906160e7565b5f86815260a46020526040902060010154909150615498908290616045565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a5909152812080549091906154e4908490616045565b90915550506040516154f7908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061556b90846162c2565b61557591906162d9565b90506155818183616058565b60aa5f8282546155919190616045565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a56020526040812080548392906155ca908490616045565b90915550506040516155dd908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b80156156fb575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615689576040519150601f19603f3d011682016040523d82523d5f602084013e61568e565b606091505b50509050806156f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c1a565b505b5050565b615707614655565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861575a3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b61578c615b53565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361575a565b5f81615843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c1a565b82825f81811061585557615855616311565b919091013560f81c949350505050565b5f8160f98110156158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c1a565b6040519150808483378082016040529250929050565b5f8161010181146158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c1a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f91810161598a8161ffff871686615bbf565b82900390912095945050505050565b8082535050565b60605f808080806159b3888a018a61642b565b95509550955095509550508187106159d15794506159ed9350505050565b8387106159e55782955050505050506159ed565b509293505050505b9392505050565b5f54610100900460ff16615a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff16615b4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b61288833615212565b60655460ff16612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c1a565b5f825f03615bce5750826159ed565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b84811015615c95576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa158015615c5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190615c8091906160e7565b87525060209095019460019384019301615be9565b5093949350505050565b5f60208284031215615caf575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114615033575f80fd5b5f60208284031215615ce9575f80fd5b6159ed82615cb6565b5f8083601f840112615d02575f80fd5b50813567ffffffffffffffff811115615d19575f80fd5b602083019150836020828501011115615d30575f80fd5b9250929050565b5f805f60408486031215615d49575f80fd5b833567ffffffffffffffff811115615d5f575f80fd5b615d6b86828701615cf2565b909790965060209590950135949350505050565b5f8060208385031215615d90575f80fd5b823567ffffffffffffffff811115615da6575f80fd5b615db285828601615cf2565b90969095509350505050565b5f60e08284031215614f6c575f80fd5b5f60608284031215614f6c575f80fd5b5f8060408385031215615def575f80fd5b823567ffffffffffffffff80821115615e06575f80fd5b615e1286838701615dbe565b93506020850135915080821115615e27575f80fd5b50615e3485828601615dce565b9150509250929050565b5f805f805f8060808789031215615e53575f80fd5b863567ffffffffffffffff80821115615e6a575f80fd5b615e768a838b01615dbe565b97506020890135915080821115615e8b575f80fd5b615e978a838b01615dce565b96506040890135915080821115615eac575f80fd5b615eb88a838b01615cf2565b90965094506060890135915080821115615ed0575f80fd5b50615edd89828a01615cf2565b979a9699509497509295939492505050565b5f805f805f8060c08789031215615f04575f80fd5b615f0d87615cb6565b9550615f1b60208801615cb6565b9450615f2960408801615cb6565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f8060408587031215615f5d575f80fd5b843567ffffffffffffffff80821115615f74575f80fd5b615f8088838901615cf2565b90965094506020870135915080821115615f98575f80fd5b50615fa587828801615cf2565b95989497509550505050565b80151581146138b2575f80fd5b5f60208284031215615fce575f80fd5b81356159ed81615fb1565b803567ffffffffffffffff81168114615033575f80fd5b5f8060408385031215616001575f80fd5b61600a83615fd9565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611b8c57611b8c616018565b81810381811115611b8c57611b8c616018565b5f6020828403121561607b575f80fd5b81516159ed81615fb1565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126160b9575f80fd5b83018035915067ffffffffffffffff8211156160d3575f80fd5b602001915036819003821315615d30575f80fd5b5f602082840312156160f7575f80fd5b5051919050565b5f6020828403121561610e575f80fd5b813561ffff811681146159ed575f80fd5b5f6020828403121561612f575f80fd5b813560ff811681146159ed575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361616f5761616f616018565b5060010190565b5f60208284031215616186575f80fd5b6159ed82615fd9565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b8181101561623c57845173ffffffffffffffffffffffffffffffffffffffff168352938301939183019160010161620a565b5050876040860152848103606086015261625781878961619e565b9a9950505050505050505050565b858152846020820152608060408201525f61628460808301858761619e565b90508260608301529695505050505050565b5f82515f5b818110156162b5576020818601810151858301520161629b565b505f920191825250919050565b8082028115828204841417611b8c57611b8c616018565b5f8261630c577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261637a575f80fd5b8135602067ffffffffffffffff808311156163975761639761633e565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156163da576163da61633e565b60405293845260208187018101949081019250878511156163f9575f80fd5b6020870191505b848210156164205761641182615cb6565b83529183019190830190616400565b979650505050505050565b5f805f805f8060c08789031215616440575f80fd5b86359550602087013567ffffffffffffffff8082111561645e575f80fd5b61646a8a838b0161636b565b9650604089013595506060890135915080821115616486575f80fd5b6164928a838b0161636b565b94506080890135935060a08901359150808211156164ae575f80fd5b506164bb89828a0161636b565b915050929550929550929556fea164736f6c6343000818000a" +var RollupDeployedBin = "0x608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610ba1578063f2fde38b14610bc0578063f8fa010f14610bdf578063fb1e8b0414610bfe575f80fd5b8063d279c19114610b39578063d8dc99d214610b58578063de8b303514610b6d578063dff7827e14610b8c575f80fd5b8063c5553892116100d8578063c555389214610ad3578063cd4edc6914610af2578063ce5db8d614610b05578063cf9a674514610b1a575f80fd5b8063b3e0a50914610a76578063b8d0a1b014610a95578063bedb86fb14610ab4575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d146109f8578063b31a77d314610a23578063b348442514610a38578063b35dac4e14610a57575f80fd5b8063a415d8dc14610996578063a479265d146109c4578063a4f209b0146109d9575f80fd5b80638f1d3776116101a35780638f1d377614610850578063910129d41461091a57806397fc007c1461094b578063a3c9e94c1461096a575f80fd5b806388b1ea09146107e25780638da5cb5b146107fb5780638ef622a814610825575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107655780636c578c1d14610790578063715018a6146107af578063728cdbca146107c3575f80fd5b80635f77cf1d146106db578063612672901461072757806367caa37a14610746575f80fd5b806341f756da1161027957806341f756da1461060657806357e0af6c146106195780635c975abb146106385780635ef7a94a1461064f575f80fd5b80632b7ac3f3146105745780633b70c18a146105c55780633e001b66146105f1575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e3660046162b5565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046162ef565b610c13565b005b348015610406575f80fd5b506103f961041536600461634d565b610d37565b348015610425575f80fd5b506103a26104343660046162b5565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004616395565b61112c565b34801561047b575f80fd5b506103f961048a3660046163e4565b611777565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be3660046162b5565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee3660046162b5565b611bec565b3480156104fe575f80fd5b506103cc61050d3660046162b5565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc6105383660046162b5565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc6105633660046162b5565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103ae565b3480156105d0575f80fd5b50609b546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105fc575f80fd5b506103cc60aa5481565b6103f9610614366004616472565b611c1a565b348015610624575f80fd5b506103f96106333660046162b5565b611f47565b348015610643575f80fd5b5060655460ff166103a2565b34801561065a575f80fd5b506106a56106693660046162b5565b60a26020525f908152604090208054600182015460028301546003909301549192909173ffffffffffffffffffffffffffffffffffffffff1684565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080016103ae565b3480156106e6575f80fd5b5061070e7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b348015610732575f80fd5b506103f96107413660046162b5565b61200c565b348015610751575f80fd5b506103f9610760366004616472565b612271565b348015610770575f80fd5b506103cc61077f3660046162b5565b60ab6020525f908152604090205481565b34801561079b575f80fd5b506103f96107aa3660046162ef565b612665565b3480156107ba575f80fd5b506103f9612774565b3480156107ce575f80fd5b506103f96107dd3660046164ac565b612787565b3480156107ed575f80fd5b5060a6546103a29060ff1681565b348015610806575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff166105a0565b348015610830575f80fd5b506103cc61083f3660046162ef565b60ae6020525f908152604090205481565b34801561085b575f80fd5b506108c961086a3660046162b5565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b348015610925575f80fd5b506103a26109343660046162b5565b5f90815260a4602052604090206003015460ff1690565b348015610956575f80fd5b506103f96109653660046162ef565b612b50565b348015610975575f80fd5b506097546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a1575f80fd5b506103a26109b03660046162ef565b609f6020525f908152604090205460ff1681565b3480156109cf575f80fd5b506103cc60995481565b3480156109e4575f80fd5b506103f96109f33660046162b5565b612c74565b348015610a03575f80fd5b506103cc610a123660046162ef565b60a56020525f908152604090205481565b348015610a2e575f80fd5b506103cc60a85481565b348015610a43575f80fd5b506103f9610a52366004616507565b612d3e565b348015610a62575f80fd5b506103f9610a713660046162ef565b613133565b348015610a81575f80fd5b506103f9610a90366004616395565b613199565b348015610aa0575f80fd5b506103f9610aaf366004616507565b6135d3565b348015610abf575f80fd5b506103f9610ace36600461657b565b613676565b348015610ade575f80fd5b506103f9610aed3660046162b5565b613809565b6103f9610b003660046165ad565b6138c6565b348015610b10575f80fd5b506103cc60985481565b348015610b25575f80fd5b506103f9610b343660046162b5565b613fdb565b348015610b44575f80fd5b506103f9610b533660046162ef565b6141c0565b348015610b63575f80fd5b506103cc60ac5481565b348015610b78575f80fd5b506103a2610b873660046162b5565b6142a6565b348015610b97575f80fd5b506103cc609a5481565b348015610bac575f80fd5b506103f9610bbb3660046162b5565b6142fd565b348015610bcb575f80fd5b506103f9610bda3660046162ef565b6143ba565b348015610bea575f80fd5b506103f9610bf93660046162ef565b61446e565b348015610c09575f80fd5b506103cc60a95481565b610c1b614aa4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610caf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610d3f614aa4565b5f8111610da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610ca6565b5f80610db48585614b25565b915091505f610dc7836001015160c01c90565b5f81815260a160205260409020549091508214610e40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b5f60a181610e4e8785616602565b81526020019081526020015f205414610ee8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b609d548111610f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b610f84600182616615565b609e555b831561112457604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610fc281614be7565b5f81815260a16020526040812055610fd9816142a6565b1561105f575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091611031908490616602565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a854158015906110dc575060a85481145b156110e6575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610f88575b505050505050565b60a85415611196576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b61119e614cdb565b5f806111aa8484614b25565b915091505f6111bd836001015160c01c90565b5f81815260a160205260409020549091508214611236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b61123f81611bec565b6112a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca6565b6112ae816142a6565b15611315576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610ca6565b5f81815260a4602052604090206003015460ff1615611390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610ca6565b5f81815260a2602052604090206001015442101561140a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610ca6565b605983015160a05f61141d600185616615565b81526020019081526020015f205414611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca6565b5f81815260a0602052604090205415611507576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610ca6565b80609d5460010114611575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca6565b609d819055600160a35f61158a866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a060205260409020556115f76115ea846011015160c01c90565b600985015160c01c614d48565b61160081614be7565b60a25f61160e600184616615565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab919061166a9084616615565b81526020019081526020015f205f905560ad5f60018361168a9190616615565b81526020019081526020015f205f905560a45f6001836116aa9190616615565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611753866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156117e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6117e9614cdb565b60ac54609e545f90815260a260205260408120549091429161180b9190616602565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118a19190616628565b6118ab9190616602565b109050811580156118b95750805b1561193a575f6118cf6080890160608a0161663f565b61ffff161161193a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b81806119435750805b6119a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610ca6565b5f6119bf6119ba60208a018a616660565b614b25565b5090505f6119d1826001015160c01c90565b6119dc906001616602565b5f81815260ad60205260408120549192509015611a96575f4915611a82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610ca6565b505f81815260ad6020526040902054611ab1565b611aae611aa660208c018c6166c1565b60ff16614e12565b90505b611abc8a5f83614f81565b5f80611ac88b8b614b25565b915091505f611adb836001015160c01c90565b905080609e5414611b48576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610ca6565b5f81815260a160205260409020548214611bbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b5f81815260a26020526040902042600190910155611bdd838b8b6155a6565b50505050505050505050505050565b5f81815260a2602052604081205415801590611c1457505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611ca0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cc491906166e1565b611d2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b60a85415611d94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b611d9c614cdb565b5f49611e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610ca6565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e75573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e999190616628565b611ea39190616602565b1015611f25575f611eba608083016060840161663f565b61ffff1611611f25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b5f611f36611aa660208401846166c1565b9050611f43823383614f81565b5050565b611f4f614aa4565b5f81118015611f6057506099548114155b611fc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610ca6565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561202c57505f5460ff8083169116105b6120b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556120f0614aa4565b5f5460ff1660ff16600214612161576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610ca6565b816121ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610ca6565b609e545f90815260ab602052604090205461221757609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa1580156122f7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061231b91906166e1565b612381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b60a854156123eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6123f3614cdb565b5f491561245c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610ca6565b5f61246d6119ba6020840184616660565b5090505f61247f826001015160c01c90565b61248a906001616602565b5f81815260ad6020526040902054909150612527576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015612598573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bc9190616628565b6125c69190616602565b1015612648575f6125dd608085016060860161663f565b61ffff1611612648576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b61266083335f84815260ad6020526040902054614f81565b505050565b61266d614aa4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff166126fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610ca6565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610d2c565b61277c614aa4565b6127855f615780565b565b5f54610100900460ff16158080156127a557505f54600160ff909116105b806127be5750303b1580156127be57505f5460ff166001145b61284a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156128a6575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806128dd575073ffffffffffffffffffffffffffffffffffffffff8516155b15612914576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8716612991576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610ca6565b6129996157f6565b6129a1615894565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612b47575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612b58614aa4565b73ffffffffffffffffffffffffffffffffffffffff811615801590612b985750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612bfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610ca6565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612c7c614aa4565b5f81118015612c8c575060648111155b8015612c9a575060a9548114155b612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610ca6565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101612000565b60a85415612da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b612db0614cdb565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612e36573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e5a91906166e1565b612ec0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b5f80612ecc8686614b25565b915091505f612edf836001015160c01c90565b5f81815260a160205260409020549091508214612f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b612f61816142a6565b612fc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610ca6565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161303e91616602565b116130e8575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526130e391839173ffffffffffffffffffffffffffffffffffffffff1690615932565b612b47565b6130f38386866155a6565b612b4781336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615ab8565b61313b614aa4565b60aa80545f90915561314d8282615b9e565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101612000565b6131a1614aa4565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415613232576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610ca6565b5f8061323e8484614b25565b915091505f613251836001015160c01c90565b905080156132bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610ca6565b5f6132c7846079015190565b905080613330576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610ca6565b600984015160c01c1561339f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610ca6565b5f6133ab856019015190565b03613412576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610ca6565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461343e856039015190565b146134a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610ca6565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f806135df8686614b25565b915091505f6135f2836001015160c01c90565b5f81815260a16020526040902054909150821461366b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b612b478386866155a6565b61367e614aa4565b80156137d75761368c615c6a565b60a65460ff16156137895760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a590925282208054919290916136ed908490616602565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b6137df615cef565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336137ac565b50565b613811614aa4565b5f81118015613822575060ac548114155b613888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610ca6565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101612000565b335f908152609f602052604090205460ff1661393e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610ca6565b60a854156139a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6139b0614cdb565b60a65460ff1615613a1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610ca6565b8167ffffffffffffffff16609d5410613a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a160205260409020548114613b13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b613b268267ffffffffffffffff16611bec565b613b8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613c2e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a260205260409020600101544210613cd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610ca6565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d42573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d669190616628565b341015613dcf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610ca6565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613f3b91815260200190565b60405180910390a35f609d546001613f539190616602565b90505b609e548111613fab578267ffffffffffffffff168114613f99576099545f82815260a2602052604081206001018054909190613f93908490616602565b90915550505b80613fa3816166fc565b915050613f56565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff16158015613ffb57505f5460ff8083169116105b614087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556140bf614aa4565b815f03614128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610ca6565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b335f90815260a5602052604081205490819003614239576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610ca6565b335f90815260a560205260408120556142528282615b9e565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161429a91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611c145750505f90815260a46020526040902060030154610100900460ff161590565b614305614aa4565b5f8111801561431657506098548114155b61437c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610ca6565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101612000565b6143c2614aa4565b73ffffffffffffffffffffffffffffffffffffffff8116614465576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ca6565b61380681615780565b5f54600490610100900460ff1615801561448e57505f5460ff8083169116105b61451a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff831617610100179055614552614aa4565b73ffffffffffffffffffffffffffffffffffffffff82161580159061458d57505f8273ffffffffffffffffffffffffffffffffffffffff163b115b6145f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610ca6565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90614657908490615d46565b905060a081901c156146c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610ca6565b6040515f602482018190528291614756908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052615d46565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f906147bd908790615d46565b905073ffffffffffffffffffffffffffffffffffffffff8316301461483e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610ca6565b8115801561484b57505f81115b6148b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610ca6565b609d54609e541461491e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610ca6565b60a85415614988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055609754905173ffffffffffffffffffffffffffffffffffffffff898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861617905550505f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b60335473ffffffffffffffffffffffffffffffffffffffff163314612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca6565b5f805f614b328585615de9565b90505f8160ff165f03614b5357614b498686615e73565b9094509050614bd9565b8160ff1660011480614b6857508160ff166002145b15614b7757614b498686615ef6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610ca6565b808420925050509250929050565b5f81815260a2602052604090206003015473ffffffffffffffffffffffffffffffffffffffff1680614c17575050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ae602052604090205480614ca3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610ca6565b614cae600182616615565b73ffffffffffffffffffffffffffffffffffffffff9092165f90815260ae60205260409020919091555050565b60655460ff1615612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610ca6565b805f03614d53575050565b8082035f5b82811015614e0c57610100818403811115614d7257508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b158015614de2575f80fd5b505af1158015614df4573d5f803e3d5ffd5b50505050610100830192505061010081019050614d58565b50505050565b5f81600203614ebb575f6040515f5b804980614e2e5750614e3d565b60208202830152600101614e21565b602081028083209201604052909250905080614eb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610ca6565b50919050565b60014915614f4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610ca6565b5f4915614f59575f49611c14565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002614f9060208501856166c1565b60ff161115614ffb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610ca6565b6080830135615066576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610ca6565b60a08301356150d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610ca6565b5f806150e36119ba6020870187616660565b915091505f6150f6836001015160c01c90565b90505f60a181615107846001616602565b81526020019081526020015f20541461517c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610ca6565b609e5481146151e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca6565b5f81815260a16020526040902054821461525d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610ca6565b5f81815260ab60205260409020546080870135146152d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca6565b5f6152e6846011015160c01c90565b90505f6153126152fc60608a0160408b01616733565b61530c60808b0160608c0161663f565b84615f63565b90506153246080890160608a0161663f565b60019384019361ffff91909116929092019160f99061534660208b018b6166c1565b60ff161061535357506101015b6040805182810190915295506153788661537060208c018c6166c1565b60ff16615fa7565b60c084901b60018701526153a68661539660808c0160608d0161663f565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d9860185905260016153f660208b018b6166c1565b60ff1610615428576154288661541260608c0160408d01616733565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156154915760a7545f90815260a46020526040902060020154609954429161548491616602565b61548e9190616615565b90505b604051806080016040528042815260200182609854426154b19190616602565b6154bb9190616602565b81526020016154d060608d0160408e01616733565b67ffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561555c89615fae565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b8061560d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610ca6565b5f61561c846001015160c01c90565b90505f61562a856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000615659876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a848615728885160f81c90565b858888866040518663ffffffff1660e01b815260040161574c95949392919061674c565b5f6040518083038186803b158015615762575f80fd5b505afa158015615774573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff1661588c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b612785616007565b5f54610100900460ff1661592a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b6127856160c7565b60a88390555f83815260a460205260408082205460975491517fc96be4cb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af11580156159c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906159ea9190616628565b5f86815260a46020526040902060010154909150615a09908290616602565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a590915281208054909190615a55908490616602565b9091555050604051615a689084906167af565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490615adc90846167db565b615ae691906167f2565b9050615af28183616615565b60aa5f828254615b029190616602565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a5602052604081208054839290615b3b908490616602565b9091555050604051615b4e9084906167af565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611f43575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615bfa576040519150601f19603f3d011682016040523d82523d5f602084013e615bff565b606091505b5050905080612660576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610ca6565b615c72614cdb565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258615cc53390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b615cf7616166565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33615cc5565b5f805f805f855160208701885afa91503d905060208114821615615d6e5760205f803e5f5192505b818015615d7b5750806020145b615de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610ca6565b505092915050565b5f81615e51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610ca6565b82825f818110615e6357615e6361682a565b919091013560f81c949350505050565b5f8160f9811015615ee0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610ca6565b6040519150808483378082016040529250929050565b5f816101018114615ee0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610ca6565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101615f988161ffff8716866161d2565b82900390912095945050505050565b8082535050565b73ffffffffffffffffffffffffffffffffffffffff8116156138065773ffffffffffffffffffffffffffffffffffffffff81165f90815260ae60205260408120805460019290615fff908490616602565b909155505050565b5f54610100900460ff1661609d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff1661615d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b61278533615780565b60655460ff16612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610ca6565b5f825f036161e15750826162ae565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b848110156162a8576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa15801561626f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906162939190616628565b875250602090950194600193840193016161fc565b50849150505b9392505050565b5f602082840312156162c5575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614f7c575f80fd5b5f602082840312156162ff575f80fd5b6162ae826162cc565b5f8083601f840112616318575f80fd5b50813567ffffffffffffffff81111561632f575f80fd5b602083019150836020828501011115616346575f80fd5b9250929050565b5f805f6040848603121561635f575f80fd5b833567ffffffffffffffff811115616375575f80fd5b61638186828701616308565b909790965060209590950135949350505050565b5f80602083850312156163a6575f80fd5b823567ffffffffffffffff8111156163bc575f80fd5b6163c885828601616308565b90969095509350505050565b5f60e08284031215614eb5575f80fd5b5f805f805f606086880312156163f8575f80fd5b853567ffffffffffffffff8082111561640f575f80fd5b61641b89838a016163d4565b96506020880135915080821115616430575f80fd5b61643c89838a01616308565b90965094506040880135915080821115616454575f80fd5b5061646188828901616308565b969995985093965092949392505050565b5f60208284031215616482575f80fd5b813567ffffffffffffffff811115616498575f80fd5b6164a4848285016163d4565b949350505050565b5f805f805f8060c087890312156164c1575f80fd5b6164ca876162cc565b95506164d8602088016162cc565b94506164e6604088016162cc565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561651a575f80fd5b843567ffffffffffffffff80821115616531575f80fd5b61653d88838901616308565b90965094506020870135915080821115616555575f80fd5b5061656287828801616308565b95989497509550505050565b8015158114613806575f80fd5b5f6020828403121561658b575f80fd5b81356162ae8161656e565b803567ffffffffffffffff81168114614f7c575f80fd5b5f80604083850312156165be575f80fd5b6165c783616596565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611c1457611c146165d5565b81810381811115611c1457611c146165d5565b5f60208284031215616638575f80fd5b5051919050565b5f6020828403121561664f575f80fd5b813561ffff811681146162ae575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112616693575f80fd5b83018035915067ffffffffffffffff8211156166ad575f80fd5b602001915036819003821315616346575f80fd5b5f602082840312156166d1575f80fd5b813560ff811681146162ae575f80fd5b5f602082840312156166f1575f80fd5b81516162ae8161656e565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361672c5761672c6165d5565b5060010190565b5f60208284031215616743575f80fd5b6162ae82616596565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156167ce57602081860181015185830152016167b4565b505f920191825250919050565b8082028115828204841417611c1457611c146165d5565b5f82616825577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a" func init() { if err := json.Unmarshal([]byte(RollupStorageLayoutJSON), RollupStorageLayout); err != nil { diff --git a/bindings/bindings/submitter.go b/bindings/bindings/submitter.go new file mode 100644 index 000000000..9361dc2f0 --- /dev/null +++ b/bindings/bindings/submitter.go @@ -0,0 +1,2863 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// SubmitterMetaData contains all meta data concerning the Submitter contract. +var SubmitterMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CreditClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"MinimumStakeUpdated\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalCredit\",\"type\":\"uint256\"}],\"name\":\"WithdrawalCredited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"addSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimCredit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"claimable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"exiting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isExiting\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rollupContract_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardPercentage_\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"isActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"registered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"removeSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setMinimumStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"stakeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561000f575f80fd5b5061001861001d565b6100d9565b5f54610100900460ff16156100885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100d7575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611df9806100e65f395ff3fe60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd111461044a578063d13f90b414610469578063ec5ffac214610488578063f2fde38b1461049d575f80fd5b8063bfa02ba9146103ed578063c36f41e21461040c578063c96be4cb1461042b575f80fd5b8063ab8c53dc116100b7578063ab8c53dc1461037c578063b2dd5c0714610391578063bbfefd38146103bf575f80fd5b80639f8a13d71461030f578063a3066aab1461033e578063a4f209b01461035d575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac366004611cca565b6104bc565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f5366004611cea565b6105b4565b348015610205575f80fd5b506101b1610214366004611cea565b61065a565b6101b1610700565b34801561022c575f80fd5b506101c861023b366004611cca565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c8610266366004611cca565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b1610291366004611cca565b61086e565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c5366004611cca565b610a06565b3480156102d5575f80fd5b506101b1610b45565b3480156102e9575f80fd5b506033546001600160a01b03165b6040516001600160a01b0390911681526020016101d2565b34801561031a575f80fd5b5061032e610329366004611cca565b610b56565b60405190151581526020016101d2565b348015610349575f80fd5b506101b1610358366004611cca565b610bc0565b348015610368575f80fd5b506101b1610377366004611cea565b610ce5565b348015610387575f80fd5b506101c8609b5481565b34801561039c575f80fd5b5061032e6103ab366004611cca565b609c6020525f908152604090205460ff1681565b3480156103ca575f80fd5b5061032e6103d9366004611cca565b609e6020525f908152604090205460ff1681565b3480156103f8575f80fd5b506097546102f7906001600160a01b031681565b348015610417575f80fd5b506101b1610426366004611cca565b610d98565b348015610436575f80fd5b506101c8610445366004611cca565b610ef8565b348015610455575f80fd5b506101b1610464366004611cca565b611064565b348015610474575f80fd5b506101b1610483366004611d01565b611176565b348015610493575f80fd5b506101c860985481565b3480156104a8575f80fd5b506101b16104b7366004611cca565b61158a565b6104c4611617565b6001600160a01b038116158015906104f457506001600160a01b0381165f908152609c602052604090205460ff16155b801561051857506001600160a01b0381165f908152609e602052604090205460ff16155b6105695760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105bc611617565b5f811180156105cd57506098548114155b6106195760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610662611617565b5f8111801561067357506099548114155b6106bf5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610708611671565b335f818152609c602052604090205460ff16801561073e57506001600160a01b0381165f908152609e602052604090205460ff16155b61078a5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609d60205260408120546107ad903490611d77565b90505f341180156107c057506098548110155b61080c5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610560565b6001600160a01b0382165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061086c6001606555565b565b610876611671565b336001600160a01b0382166108cd5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609c602052604090205460ff16801561090c57506001600160a01b0381165f908152609e602052604090205460ff16155b801561092e57506001600160a01b0381165f908152609d602052604090205415155b61097a5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610560565b6001600160a01b038181165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a36109f881836116d1565b50610a036001606555565b50565b610a0e611671565b336001600160a01b038216610a655760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609f602052604090205480610aca5760405162461bcd60e51b815260206004820152600960248201527f6e6f2063726564697400000000000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0382165f908152609f6020526040812055610aec83826116ed565b826001600160a01b0316826001600160a01b03167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610b3191815260200190565b60405180910390a35050610a036001606555565b610b4d611617565b61086c5f61179c565b6001600160a01b0381165f908152609c602052604081205460ff168015610b9557506001600160a01b0382165f908152609e602052604090205460ff16155b8015610bba57506098546001600160a01b0383165f908152609d602052604090205410155b92915050565b610bc8611671565b336001600160a01b038216610c1f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609e602052604090205460ff16610c865760405162461bcd60e51b815260206004820152600b60248201527f6e6f742065786974696e670000000000000000000000000000000000000000006044820152606401610560565b610c8f81611805565b610cdb5760405162461bcd60e51b815260206004820152601760248201527f70656e64696e67206261746368206c696162696c6974790000000000000000006044820152606401610560565b6109f881836118f0565b610ced611617565b5f81118015610cfd575060648111155b8015610d0b5750609a548114155b610d575760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610da0611617565b610da8611671565b6001600160a01b0381165f908152609c602052604090205460ff168015610de757506001600160a01b0381165f908152609e602052604090205460ff16155b610e335760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f818152609c60209081526040808320805460ff19908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a26001600160a01b0381165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b3291610edc91815260200190565b60405180910390a3610eee81826116d1565b610a036001606555565b6097545f906001600160a01b0316336001600160a01b031614610f5d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610560565b610f65611671565b6001600160a01b038216610f7a57505f611055565b6001600160a01b0382165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216600117909155609a54606490610fce9083611d8a565b610fd89190611da1565b9150610fe48282611dd9565b609b5f828254610ff49190611d77565b909155505060975461100f906001600160a01b0316836116ed565b60408051828152602081018490526001600160a01b038516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61105f6001606555565b919050565b61106c611617565b611074611671565b6001600160a01b0381166110ca5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b609b548061111a5760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610560565b5f609b5561112882826116ed565b816001600160a01b03167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161116391815260200190565b60405180910390a250610a036001606555565b5f54610100900460ff161580801561119457505f54600160ff909116105b806111ad5750303b1580156111ad57505f5460ff166001145b61121f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610560565b5f805460ff19166001179055801561125d575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0386166112b35760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610560565b6001600160a01b038516158015906112d457505f856001600160a01b03163b115b6113205760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610560565b5f841161136f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b5f83116113be5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b5f821180156113ce575060648211155b61141a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b611422611aab565b61142a611b2f565b6114338661179c565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611582575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611592611617565b6001600160a01b03811661160e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610560565b610a038161179c565b6033546001600160a01b0316331461086c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610560565b6002606554036116c35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610560565b6002606555565b6001606555565b6116da82611805565b156116e9576116e982826118f0565b5050565b805f036116f8575050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611741576040519150601f19603f3d011682016040523d82523d5f602084013e611746565b606091505b50509050806117975760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610560565b505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6040516001600160a01b03821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a80000000000000000000000000000000000000000000000000000000017815260975482519293506001600160a01b0316915f9182918291829182918761c350fa92503d9150602082148316156118ce5760205f803e505f515b8280156118db5750816020145b80156118e5575080155b979650505050505050565b6001600160a01b0382165f908152609d60209081526040808320805490849055609e9092528220805460ff191690559081900361197957816001600160a01b0316836001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f60405161196c91815260200190565b60405180910390a3505050565b5f826001600160a01b03168261c350906040515f60405180830381858888f193505050503d805f81146119c7576040519150601f19603f3d011682016040523d82523d5f602084013e6119cc565b606091505b505090508015611a2857826001600160a01b0316846001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f4684604051611a1b91815260200190565b60405180910390a3611aa5565b6001600160a01b0384165f908152609f602052604081208054849290611a4f908490611d77565b90915550506001600160a01b0384165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff16611b275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611bb3565b5f54610100900460ff16611bab5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611c38565b5f54610100900460ff16611c2f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c3361179c565b5f54610100900460ff166116ca5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b80356001600160a01b038116811461105f575f80fd5b5f60208284031215611cda575f80fd5b611ce382611cb4565b9392505050565b5f60208284031215611cfa575f80fd5b5035919050565b5f805f805f60a08688031215611d15575f80fd5b611d1e86611cb4565b9450611d2c60208701611cb4565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610bba57610bba611d4a565b8082028115828204841417610bba57610bba611d4a565b5f82611dd4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610bba57610bba611d4a56fea164736f6c6343000818000a", +} + +// SubmitterABI is the input ABI used to generate the binding from. +// Deprecated: Use SubmitterMetaData.ABI instead. +var SubmitterABI = SubmitterMetaData.ABI + +// SubmitterBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SubmitterMetaData.Bin instead. +var SubmitterBin = SubmitterMetaData.Bin + +// DeploySubmitter deploys a new Ethereum contract, binding an instance of Submitter to it. +func DeploySubmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Submitter, error) { + parsed, err := SubmitterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SubmitterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil +} + +// Submitter is an auto generated Go binding around an Ethereum contract. +type Submitter struct { + SubmitterCaller // Read-only binding to the contract + SubmitterTransactor // Write-only binding to the contract + SubmitterFilterer // Log filterer for contract events +} + +// SubmitterCaller is an auto generated read-only Go binding around an Ethereum contract. +type SubmitterCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SubmitterTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SubmitterFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SubmitterSession struct { + Contract *Submitter // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SubmitterCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SubmitterCallerSession struct { + Contract *SubmitterCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SubmitterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SubmitterTransactorSession struct { + Contract *SubmitterTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SubmitterRaw is an auto generated low-level Go binding around an Ethereum contract. +type SubmitterRaw struct { + Contract *Submitter // Generic contract binding to access the raw methods on +} + +// SubmitterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SubmitterCallerRaw struct { + Contract *SubmitterCaller // Generic read-only contract binding to access the raw methods on +} + +// SubmitterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SubmitterTransactorRaw struct { + Contract *SubmitterTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSubmitter creates a new instance of Submitter, bound to a specific deployed contract. +func NewSubmitter(address common.Address, backend bind.ContractBackend) (*Submitter, error) { + contract, err := bindSubmitter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil +} + +// NewSubmitterCaller creates a new read-only instance of Submitter, bound to a specific deployed contract. +func NewSubmitterCaller(address common.Address, caller bind.ContractCaller) (*SubmitterCaller, error) { + contract, err := bindSubmitter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SubmitterCaller{contract: contract}, nil +} + +// NewSubmitterTransactor creates a new write-only instance of Submitter, bound to a specific deployed contract. +func NewSubmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*SubmitterTransactor, error) { + contract, err := bindSubmitter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SubmitterTransactor{contract: contract}, nil +} + +// NewSubmitterFilterer creates a new log filterer instance of Submitter, bound to a specific deployed contract. +func NewSubmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*SubmitterFilterer, error) { + contract, err := bindSubmitter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SubmitterFilterer{contract: contract}, nil +} + +// bindSubmitter binds a generic wrapper to an already deployed contract. +func bindSubmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SubmitterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Submitter *SubmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Submitter.Contract.SubmitterCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Submitter *SubmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.Contract.SubmitterTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Submitter *SubmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Submitter.Contract.SubmitterTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Submitter *SubmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Submitter.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Submitter *SubmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Submitter *SubmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Submitter.Contract.contract.Transact(opts, method, params...) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "challengeDeposit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterSession) ChallengeDeposit() (*big.Int, error) { + return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterCallerSession) ChallengeDeposit() (*big.Int, error) { + return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) +} + +// Claimable is a free data retrieval call binding the contract method 0x402914f5. +// +// Solidity: function claimable(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCaller) Claimable(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "claimable", submitter) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Claimable is a free data retrieval call binding the contract method 0x402914f5. +// +// Solidity: function claimable(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterSession) Claimable(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.Claimable(&_Submitter.CallOpts, submitter) +} + +// Claimable is a free data retrieval call binding the contract method 0x402914f5. +// +// Solidity: function claimable(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCallerSession) Claimable(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.Claimable(&_Submitter.CallOpts, submitter) +} + +// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. +// +// Solidity: function exiting(address submitter) view returns(bool isExiting) +func (_Submitter *SubmitterCaller) Exiting(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "exiting", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. +// +// Solidity: function exiting(address submitter) view returns(bool isExiting) +func (_Submitter *SubmitterSession) Exiting(submitter common.Address) (bool, error) { + return _Submitter.Contract.Exiting(&_Submitter.CallOpts, submitter) +} + +// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. +// +// Solidity: function exiting(address submitter) view returns(bool isExiting) +func (_Submitter *SubmitterCallerSession) Exiting(submitter common.Address) (bool, error) { + return _Submitter.Contract.Exiting(&_Submitter.CallOpts, submitter) +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterCaller) IsActive(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "isActive", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterSession) IsActive(submitter common.Address) (bool, error) { + return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterCallerSession) IsActive(submitter common.Address) (bool, error) { + return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterCaller) MinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "minimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterSession) MinimumStake() (*big.Int, error) { + return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterCallerSession) MinimumStake() (*big.Int, error) { + return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterSession) Owner() (common.Address, error) { + return _Submitter.Contract.Owner(&_Submitter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterCallerSession) Owner() (common.Address, error) { + return _Submitter.Contract.Owner(&_Submitter.CallOpts) +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterCaller) Registered(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "registered", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterSession) Registered(submitter common.Address) (bool, error) { + return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterCallerSession) Registered(submitter common.Address) (bool, error) { + return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "rewardPercentage") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterSession) RewardPercentage() (*big.Int, error) { + return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterCallerSession) RewardPercentage() (*big.Int, error) { + return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "rollupContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterSession) RollupContract() (common.Address, error) { + return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterCallerSession) RollupContract() (common.Address, error) { + return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "slashRemaining") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterSession) SlashRemaining() (*big.Int, error) { + return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterCallerSession) SlashRemaining() (*big.Int, error) { + return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCaller) StakeOf(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "stakeOf", submitter) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterSession) StakeOf(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCallerSession) StakeOf(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactor) AddSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "addSubmitter", submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactorSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address receiver) returns() +func (_Submitter *SubmitterTransactor) ClaimCredit(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "claimCredit", receiver) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address receiver) returns() +func (_Submitter *SubmitterSession) ClaimCredit(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimCredit(&_Submitter.TransactOpts, receiver) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) ClaimCredit(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimCredit(&_Submitter.TransactOpts, receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "claimSlashRemaining", receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "claimWithdrawal", receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterTransactor) Initialize(opts *bind.TransactOpts, owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "initialize", owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterTransactorSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactor) RemoveSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "removeSubmitter", submitter) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactorSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterSession) RenounceOwnership() (*types.Transaction, error) { + return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterTransactor) SetMinimumStake(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "setMinimumStake", value) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterTransactor) Slash(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "slash", submitter) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterSession) Slash(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterTransactorSession) Slash(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterTransactor) Stake(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "stake") +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterSession) Stake() (*types.Transaction, error) { + return _Submitter.Contract.Stake(&_Submitter.TransactOpts) +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterTransactorSession) Stake() (*types.Transaction, error) { + return _Submitter.Contract.Stake(&_Submitter.TransactOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "updateChallengeDeposit", value) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "updateRewardPercentage", value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address receiver) returns() +func (_Submitter *SubmitterTransactor) Withdraw(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "withdraw", receiver) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address receiver) returns() +func (_Submitter *SubmitterSession) Withdraw(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts, receiver) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. +// +// Solidity: function withdraw(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) Withdraw(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts, receiver) +} + +// SubmitterChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the Submitter contract. +type SubmitterChallengeDepositUpdatedIterator struct { + Event *SubmitterChallengeDepositUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterChallengeDepositUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterChallengeDepositUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterChallengeDepositUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the Submitter contract. +type SubmitterChallengeDepositUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*SubmitterChallengeDepositUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return &SubmitterChallengeDepositUpdatedIterator{contract: _Submitter.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil +} + +// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterChallengeDepositUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterChallengeDepositUpdated) + if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseChallengeDepositUpdated(log types.Log) (*SubmitterChallengeDepositUpdated, error) { + event := new(SubmitterChallengeDepositUpdated) + if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterCreditClaimedIterator is returned from FilterCreditClaimed and is used to iterate over the raw logs and unpacked data for CreditClaimed events raised by the Submitter contract. +type SubmitterCreditClaimedIterator struct { + Event *SubmitterCreditClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterCreditClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterCreditClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterCreditClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterCreditClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterCreditClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterCreditClaimed represents a CreditClaimed event raised by the Submitter contract. +type SubmitterCreditClaimed struct { + Submitter common.Address + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterCreditClaimed is a free log retrieval operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. +// +// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterCreditClaimed(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterCreditClaimedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "CreditClaimed", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return &SubmitterCreditClaimedIterator{contract: _Submitter.contract, event: "CreditClaimed", logs: logs, sub: sub}, nil +} + +// WatchCreditClaimed is a free log subscription operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. +// +// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchCreditClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterCreditClaimed, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "CreditClaimed", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterCreditClaimed) + if err := _Submitter.contract.UnpackLog(event, "CreditClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseCreditClaimed is a log parse operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. +// +// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseCreditClaimed(log types.Log) (*SubmitterCreditClaimed, error) { + event := new(SubmitterCreditClaimed) + if err := _Submitter.contract.UnpackLog(event, "CreditClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Submitter contract. +type SubmitterInitializedIterator struct { + Event *SubmitterInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterInitialized represents a Initialized event raised by the Submitter contract. +type SubmitterInitialized struct { + Version uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) FilterInitialized(opts *bind.FilterOpts) (*SubmitterInitializedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &SubmitterInitializedIterator{contract: _Submitter.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *SubmitterInitialized) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterInitialized) + if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) ParseInitialized(log types.Log) (*SubmitterInitialized, error) { + event := new(SubmitterInitialized) + if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterMinimumStakeUpdatedIterator is returned from FilterMinimumStakeUpdated and is used to iterate over the raw logs and unpacked data for MinimumStakeUpdated events raised by the Submitter contract. +type SubmitterMinimumStakeUpdatedIterator struct { + Event *SubmitterMinimumStakeUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterMinimumStakeUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterMinimumStakeUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterMinimumStakeUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterMinimumStakeUpdated represents a MinimumStakeUpdated event raised by the Submitter contract. +type SubmitterMinimumStakeUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMinimumStakeUpdated is a free log retrieval operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterMinimumStakeUpdated(opts *bind.FilterOpts) (*SubmitterMinimumStakeUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "MinimumStakeUpdated") + if err != nil { + return nil, err + } + return &SubmitterMinimumStakeUpdatedIterator{contract: _Submitter.contract, event: "MinimumStakeUpdated", logs: logs, sub: sub}, nil +} + +// WatchMinimumStakeUpdated is a free log subscription operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchMinimumStakeUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterMinimumStakeUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "MinimumStakeUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterMinimumStakeUpdated) + if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMinimumStakeUpdated is a log parse operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseMinimumStakeUpdated(log types.Log) (*SubmitterMinimumStakeUpdated, error) { + event := new(SubmitterMinimumStakeUpdated) + if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Submitter contract. +type SubmitterOwnershipTransferredIterator struct { + Event *SubmitterOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterOwnershipTransferred represents a OwnershipTransferred event raised by the Submitter contract. +type SubmitterOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*SubmitterOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &SubmitterOwnershipTransferredIterator{contract: _Submitter.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SubmitterOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterOwnershipTransferred) + if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) ParseOwnershipTransferred(log types.Log) (*SubmitterOwnershipTransferred, error) { + event := new(SubmitterOwnershipTransferred) + if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the Submitter contract. +type SubmitterRewardPercentageUpdatedIterator struct { + Event *SubmitterRewardPercentageUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterRewardPercentageUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterRewardPercentageUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterRewardPercentageUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the Submitter contract. +type SubmitterRewardPercentageUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*SubmitterRewardPercentageUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return &SubmitterRewardPercentageUpdatedIterator{contract: _Submitter.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil +} + +// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterRewardPercentageUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterRewardPercentageUpdated) + if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseRewardPercentageUpdated(log types.Log) (*SubmitterRewardPercentageUpdated, error) { + event := new(SubmitterRewardPercentageUpdated) + if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the Submitter contract. +type SubmitterSlashRemainingClaimedIterator struct { + Event *SubmitterSlashRemainingClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSlashRemainingClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSlashRemainingClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSlashRemainingClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the Submitter contract. +type SubmitterSlashRemainingClaimed struct { + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts, receiver []common.Address) (*SubmitterSlashRemainingClaimedIterator, error) { + + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SlashRemainingClaimed", receiverRule) + if err != nil { + return nil, err + } + return &SubmitterSlashRemainingClaimedIterator{contract: _Submitter.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil +} + +// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashRemainingClaimed, receiver []common.Address) (event.Subscription, error) { + + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SlashRemainingClaimed", receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSlashRemainingClaimed) + if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseSlashRemainingClaimed(log types.Log) (*SubmitterSlashRemainingClaimed, error) { + event := new(SubmitterSlashRemainingClaimed) + if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the Submitter contract. +type SubmitterSlashedIterator struct { + Event *SubmitterSlashed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSlashedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSlashedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSlashedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSlashed represents a Slashed event raised by the Submitter contract. +type SubmitterSlashed struct { + Submitter common.Address + Amount *big.Int + Reward *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashed is a free log retrieval operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) FilterSlashed(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSlashedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Slashed", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSlashedIterator{contract: _Submitter.contract, event: "Slashed", logs: logs, sub: sub}, nil +} + +// WatchSlashed is a free log subscription operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashed, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Slashed", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSlashed) + if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashed is a log parse operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) ParseSlashed(log types.Log) (*SubmitterSlashed, error) { + event := new(SubmitterSlashed) + if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterStakedIterator is returned from FilterStaked and is used to iterate over the raw logs and unpacked data for Staked events raised by the Submitter contract. +type SubmitterStakedIterator struct { + Event *SubmitterStaked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterStakedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterStaked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterStaked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterStakedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterStakedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterStaked represents a Staked event raised by the Submitter contract. +type SubmitterStaked struct { + Submitter common.Address + Amount *big.Int + Total *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterStaked is a free log retrieval operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) FilterStaked(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterStakedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Staked", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterStakedIterator{contract: _Submitter.contract, event: "Staked", logs: logs, sub: sub}, nil +} + +// WatchStaked is a free log subscription operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) WatchStaked(opts *bind.WatchOpts, sink chan<- *SubmitterStaked, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Staked", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterStaked) + if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseStaked is a log parse operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) ParseStaked(log types.Log) (*SubmitterStaked, error) { + event := new(SubmitterStaked) + if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSubmitterAddedIterator is returned from FilterSubmitterAdded and is used to iterate over the raw logs and unpacked data for SubmitterAdded events raised by the Submitter contract. +type SubmitterSubmitterAddedIterator struct { + Event *SubmitterSubmitterAdded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSubmitterAddedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSubmitterAddedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSubmitterAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSubmitterAdded represents a SubmitterAdded event raised by the Submitter contract. +type SubmitterSubmitterAdded struct { + Submitter common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterAdded is a free log retrieval operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) FilterSubmitterAdded(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterAddedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterAdded", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSubmitterAddedIterator{contract: _Submitter.contract, event: "SubmitterAdded", logs: logs, sub: sub}, nil +} + +// WatchSubmitterAdded is a free log subscription operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) WatchSubmitterAdded(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterAdded, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterAdded", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSubmitterAdded) + if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterAdded is a log parse operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) ParseSubmitterAdded(log types.Log) (*SubmitterSubmitterAdded, error) { + event := new(SubmitterSubmitterAdded) + if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSubmitterRemovedIterator is returned from FilterSubmitterRemoved and is used to iterate over the raw logs and unpacked data for SubmitterRemoved events raised by the Submitter contract. +type SubmitterSubmitterRemovedIterator struct { + Event *SubmitterSubmitterRemoved // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSubmitterRemovedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSubmitterRemovedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSubmitterRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSubmitterRemoved represents a SubmitterRemoved event raised by the Submitter contract. +type SubmitterSubmitterRemoved struct { + Submitter common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterRemoved is a free log retrieval operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) FilterSubmitterRemoved(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterRemovedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterRemoved", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSubmitterRemovedIterator{contract: _Submitter.contract, event: "SubmitterRemoved", logs: logs, sub: sub}, nil +} + +// WatchSubmitterRemoved is a free log subscription operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) WatchSubmitterRemoved(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterRemoved, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterRemoved", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSubmitterRemoved) + if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterRemoved is a log parse operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) ParseSubmitterRemoved(log types.Log) (*SubmitterSubmitterRemoved, error) { + event := new(SubmitterSubmitterRemoved) + if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterWithdrawalCreditedIterator is returned from FilterWithdrawalCredited and is used to iterate over the raw logs and unpacked data for WithdrawalCredited events raised by the Submitter contract. +type SubmitterWithdrawalCreditedIterator struct { + Event *SubmitterWithdrawalCredited // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterWithdrawalCreditedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalCredited) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalCredited) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterWithdrawalCreditedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterWithdrawalCreditedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterWithdrawalCredited represents a WithdrawalCredited event raised by the Submitter contract. +type SubmitterWithdrawalCredited struct { + Submitter common.Address + Amount *big.Int + TotalCredit *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalCredited is a free log retrieval operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. +// +// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) +func (_Submitter *SubmitterFilterer) FilterWithdrawalCredited(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterWithdrawalCreditedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalCredited", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterWithdrawalCreditedIterator{contract: _Submitter.contract, event: "WithdrawalCredited", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalCredited is a free log subscription operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. +// +// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) +func (_Submitter *SubmitterFilterer) WatchWithdrawalCredited(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalCredited, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalCredited", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterWithdrawalCredited) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalCredited", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalCredited is a log parse operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. +// +// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) +func (_Submitter *SubmitterFilterer) ParseWithdrawalCredited(log types.Log) (*SubmitterWithdrawalCredited, error) { + event := new(SubmitterWithdrawalCredited) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalCredited", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterWithdrawalPaidIterator is returned from FilterWithdrawalPaid and is used to iterate over the raw logs and unpacked data for WithdrawalPaid events raised by the Submitter contract. +type SubmitterWithdrawalPaidIterator struct { + Event *SubmitterWithdrawalPaid // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterWithdrawalPaidIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalPaid) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalPaid) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterWithdrawalPaidIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterWithdrawalPaidIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterWithdrawalPaid represents a WithdrawalPaid event raised by the Submitter contract. +type SubmitterWithdrawalPaid struct { + Submitter common.Address + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalPaid is a free log retrieval operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. +// +// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterWithdrawalPaid(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterWithdrawalPaidIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalPaid", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return &SubmitterWithdrawalPaidIterator{contract: _Submitter.contract, event: "WithdrawalPaid", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalPaid is a free log subscription operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. +// +// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchWithdrawalPaid(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalPaid, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalPaid", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterWithdrawalPaid) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalPaid", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalPaid is a log parse operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. +// +// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseWithdrawalPaid(log types.Log) (*SubmitterWithdrawalPaid, error) { + event := new(SubmitterWithdrawalPaid) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalPaid", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterWithdrawalRequestedIterator is returned from FilterWithdrawalRequested and is used to iterate over the raw logs and unpacked data for WithdrawalRequested events raised by the Submitter contract. +type SubmitterWithdrawalRequestedIterator struct { + Event *SubmitterWithdrawalRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterWithdrawalRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterWithdrawalRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterWithdrawalRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterWithdrawalRequested represents a WithdrawalRequested event raised by the Submitter contract. +type SubmitterWithdrawalRequested struct { + Submitter common.Address + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalRequested is a free log retrieval operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. +// +// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterWithdrawalRequested(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterWithdrawalRequestedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalRequested", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return &SubmitterWithdrawalRequestedIterator{contract: _Submitter.contract, event: "WithdrawalRequested", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalRequested is a free log subscription operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. +// +// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchWithdrawalRequested(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalRequested, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalRequested", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterWithdrawalRequested) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalRequested is a log parse operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. +// +// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseWithdrawalRequested(log types.Log) (*SubmitterWithdrawalRequested, error) { + event := new(SubmitterWithdrawalRequested) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/bindings/bindings/submitter_more.go b/bindings/bindings/submitter_more.go new file mode 100644 index 000000000..1adc44989 --- /dev/null +++ b/bindings/bindings/submitter_more.go @@ -0,0 +1,25 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "encoding/json" + + "morph-l2/bindings/solc" +) + +const SubmitterStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1018_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"minimumStake\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"registered\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"stakeOf\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"exiting\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"claimable\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_uint256)1018_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1017_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1018_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" + +var SubmitterStorageLayout = new(solc.StorageLayout) + +var SubmitterDeployedBin = "0x60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd1114610471578063d13f90b414610490578063ec5ffac2146104af578063f2fde38b146104c4575f80fd5b8063bfa02ba914610407578063c36f41e214610433578063c96be4cb14610452575f80fd5b8063ab8c53dc116100b7578063ab8c53dc14610396578063b2dd5c07146103ab578063bbfefd38146103d9575f80fd5b80639f8a13d714610329578063a3066aab14610358578063a4f209b014610377575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac36600461237c565b6104e3565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f536600461239c565b610647565b348015610205575f80fd5b506101b161021436600461239c565b610707565b6101b16107c7565b34801561022c575f80fd5b506101c861023b36600461237c565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c861026636600461237c565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b161029136600461237c565b610990565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c536600461237c565b610bbb565b3480156102d5575f80fd5b506101b1610d6f565b3480156102e9575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b348015610334575f80fd5b5061034861034336600461237c565b610d80565b60405190151581526020016101d2565b348015610363575f80fd5b506101b161037236600461237c565b610e11565b348015610382575f80fd5b506101b161039136600461239c565b610f9e565b3480156103a1575f80fd5b506101c8609b5481565b3480156103b6575f80fd5b506103486103c536600461237c565b609c6020525f908152604090205460ff1681565b3480156103e4575f80fd5b506103486103f336600461237c565b609e6020525f908152604090205460ff1681565b348015610412575f80fd5b506097546103049073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043e575f80fd5b506101b161044d36600461237c565b61106b565b34801561045d575f80fd5b506101c861046c36600461237c565b611237565b34801561047c575f80fd5b506101b161048b36600461237c565b611429565b34801561049b575f80fd5b506101b16104aa3660046123b3565b611589565b3480156104ba575f80fd5b506101c860985481565b3480156104cf575f80fd5b506101b16104de36600461237c565b611a8b565b6104eb611b3f565b73ffffffffffffffffffffffffffffffffffffffff811615801590610535575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b8015610566575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b61064f611b3f565b5f8111801561066057506098548114155b6106c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c8565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b61070f611b3f565b5f8111801561072057506099548114155b610786576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c8565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107cf611bc0565b335f818152609c602052604090205460ff168015610812575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610878576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6e6f74207374616b6561626c650000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546108a8903490612429565b90505f341180156108bb57506098548110155b610921576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b650000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061098e6001606555565b565b610998611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610a16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610a6f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610a9e575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b610b04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420776974686472617761626c650000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff8181165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a3610bad8183611c3a565b50610bb86001606555565b50565b610bc3611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205480610ccd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f20637265646974000000000000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609f6020526040812055610cfc8382611c56565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610d5b91815260200190565b60405180910390a35050610bb86001606555565b610d77611b3f565b61098e5f611d2c565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610dd9575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610e0b575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610e19611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610f25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6e6f742065786974696e6700000000000000000000000000000000000000000060448201526064016105c8565b610f2e81611da2565b610f94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f70656e64696e67206261746368206c696162696c69747900000000000000000060448201526064016105c8565b610bad8183611ea7565b610fa6611b3f565b5f81118015610fb6575060648111155b8015610fc45750609a548114155b61102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c8565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b611073611b3f565b61107b611bc0565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff1680156110d4575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b61113a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a273ffffffffffffffffffffffffffffffffffffffff81165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b329161121b91815260200190565b60405180910390a361122d8182611c3a565b610bb86001606555565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016105c8565b6112d8611bc0565b73ffffffffffffffffffffffffffffffffffffffff82166112fa57505f61141a565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c845282852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690915591859055609e90935292208054909216600117909155609a54606490611379908361243c565b6113839190612453565b915061138f828261248b565b609b5f82825461139f9190612429565b90915550506097546113c79073ffffffffffffffffffffffffffffffffffffffff1683611c56565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6114246001606555565b919050565b611431611b3f565b611439611bc0565b73ffffffffffffffffffffffffffffffffffffffff81166114b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b609b5480611520576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e67000000000000000000000000000060448201526064016105c8565b5f609b5561152e8282611c56565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161157691815260200190565b60405180910390a250610bb86001606555565b5f54610100900460ff16158080156115a757505f54600160ff909116105b806115c05750303b1580156115c057505f5460ff166001145b61164c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016105c8565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156116a8575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8616611725576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff85161580159061176057505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6117c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016105c8565b5f841161182f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c8565b5f8311611898576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c8565b5f821180156118a8575060648211155b61190e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c8565b6119166120e8565b61191e612186565b61192786611d2c565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611a83575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611a93611b3f565b73ffffffffffffffffffffffffffffffffffffffff8116611b36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016105c8565b610bb881611d2c565b60335473ffffffffffffffffffffffffffffffffffffffff16331461098e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105c8565b600260655403611c2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105c8565b6002606555565b6001606555565b611c4382611da2565b15611c5257611c528282611ea7565b5050565b805f03611c61575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611cb7576040519150601f19603f3d011682016040523d82523d5f602084013e611cbc565b606091505b5050905080611d27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016105c8565b505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60405173ffffffffffffffffffffffffffffffffffffffff821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a800000000000000000000000000000000000000000000000000000000178152609754825192935073ffffffffffffffffffffffffffffffffffffffff16915f9182918291829182918761c350fa92503d915060208214831615611e855760205f803e505f515b828015611e925750816020145b8015611e9c575080155b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d60209081526040808320805490849055609e909252822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590819003611f75578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f604051611f6891815260200190565b60405180910390a3505050565b5f8273ffffffffffffffffffffffffffffffffffffffff168261c350906040515f60405180830381858888f193505050503d805f8114611fd0576040519150601f19603f3d011682016040523d82523d5f602084013e611fd5565b606091505b50509050801561204b578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f468460405161203e91815260200190565b60405180910390a36120e2565b73ffffffffffffffffffffffffffffffffffffffff84165f908152609f60205260408120805484929061207f908490612429565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff1661217e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e612224565b5f54610100900460ff1661221c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e6122c3565b5f54610100900460ff166122ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e33611d2c565b5f54610100900460ff16611c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b803573ffffffffffffffffffffffffffffffffffffffff81168114611424575f80fd5b5f6020828403121561238c575f80fd5b61239582612359565b9392505050565b5f602082840312156123ac575f80fd5b5035919050565b5f805f805f60a086880312156123c7575f80fd5b6123d086612359565b94506123de60208701612359565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e0b57610e0b6123fc565b8082028115828204841417610e0b57610e0b6123fc565b5f82612486577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610e0b57610e0b6123fc56fea164736f6c6343000818000a" + +func init() { + if err := json.Unmarshal([]byte(SubmitterStorageLayoutJSON), SubmitterStorageLayout); err != nil { + panic(err) + } + + layouts["Submitter"] = SubmitterStorageLayout + deployedBytecodes["Submitter"] = SubmitterDeployedBin +} diff --git a/contracts/deploy/013-DeployProxys.ts b/contracts/deploy/013-DeployProxys.ts index 6b3a4a5ce..35dd0a2ab 100644 --- a/contracts/deploy/013-DeployProxys.ts +++ b/contracts/deploy/013-DeployProxys.ts @@ -47,7 +47,7 @@ export const deployContractProxies = async ( ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName + const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -106,9 +106,9 @@ export const deployContractProxies = async ( return err } - // ************************ staking contracts deploy ************************ - // StakingProxy deploy - err = await deployContractProxyByStorageName(hre, path, deployer, L1StakingProxyStorageName) + // ************************ batch submitter contract deploy ************************ + // SubmitterProxy deploy + err = await deployContractProxyByStorageName(hre, path, deployer, SubmitterProxyStorageName) if (err != "") { return err } @@ -281,7 +281,7 @@ export const deployContractProxiesConcurrently = async ( const proxyStorageNames = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.L1StakingProxyStorageName, + ProxyStorageName.SubmitterProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, diff --git a/contracts/deploy/014-DeployImpls.ts b/contracts/deploy/014-DeployImpls.ts index b32613018..f095e1258 100644 --- a/contracts/deploy/014-DeployImpls.ts +++ b/contracts/deploy/014-DeployImpls.ts @@ -23,7 +23,7 @@ export const deployContractImplsConcurrently = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1StakingFactoryName = ContractFactoryName.L1Staking + const SubmitterFactoryName = ContractFactoryName.Submitter const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -41,7 +41,7 @@ export const deployContractImplsConcurrently = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const StakingImplStorageName = ImplStorageName.L1StakingStorageName + const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -80,18 +80,6 @@ export const deployContractImplsConcurrently = async ( await contract.deployed() console.log("%s=%s ; TX_HASH: %s", storageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - if (factoryName == L1StakingFactoryName) { - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) - } const blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) console.log(`Deployment completed for: ${storageName}`); @@ -120,7 +108,7 @@ export const deployContractImplsConcurrently = async ( deployPromises.push(deployContract(L1ERC721GatewayFactoryName, L1ERC721GatewayImplStorageName)) deployPromises.push(deployContract(L1ERC1155GatewayFactoryName, L1ERC1155GatewayImplStorageName)) - deployPromises.push(deployContract(L1StakingFactoryName, StakingImplStorageName, [L1CrossDomainMessengerProxyAddress])) + deployPromises.push(deployContract(SubmitterFactoryName, SubmitterImplStorageName)) // L1Sequencer deploy (no constructor args) const L1SequencerFactoryName = ContractFactoryName.L1Sequencer @@ -151,7 +139,7 @@ export const deployContractImpls = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1StakingFactoryName = ContractFactoryName.L1Staking + const SubmitterFactoryName = ContractFactoryName.Submitter const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -169,7 +157,7 @@ export const deployContractImpls = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const StakingImplStorageName = ImplStorageName.L1StakingStorageName + const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -364,25 +352,14 @@ export const deployContractImpls = async ( return err } - // ************************ staking contracts deploy ************************ - // Staking deploy - Factory = await hre.ethers.getContractFactory(L1StakingFactoryName) - contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) + // ************************ batch submitter contract deploy ************************ + Factory = await hre.ethers.getContractFactory(SubmitterFactoryName) + contract = await Factory.deploy() await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", StakingImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) + console.log("%s=%s ; TX_HASH: %s", SubmitterImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) - err = await storage(path, StakingImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) + err = await storage(path, SubmitterImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) if (err != '') { return err } diff --git a/contracts/deploy/015-SubmitterInstall.ts b/contracts/deploy/015-SubmitterInstall.ts new file mode 100644 index 000000000..871824c42 --- /dev/null +++ b/contracts/deploy/015-SubmitterInstall.ts @@ -0,0 +1,109 @@ +import "@nomiclabs/hardhat-ethers"; + +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ethers } from "ethers"; + +import { getContractAddressByName, storage } from "../src/deploy-utils"; +import { ContractFactoryName, ImplStorageName, ProxyStorageName } from "../src/types"; + +const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; + +export const SubmitterInstall = async ( + hre: HardhatRuntimeEnvironment, + path: string, + deployer: any, + config: any +): Promise => { + try { + const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); + const implementationAddress = getContractAddressByName(path, ImplStorageName.SubmitterStorageName); + const emptyImplementation = getContractAddressByName(path, ImplStorageName.EmptyContract); + const rollupAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName); + const owner = config.submitterOwner || config.contractAdmin; + const minimumStake = config.submitterMinimumStake; + const challengeDeposit = config.submitterChallengeDeposit; + const rewardPercentage = config.submitterRewardPercentage; + const plannedSubmitters: string[] = config.batchSubmitterAddresses || []; + + if ( + !ethers.utils.isAddress(proxyAddress) || + !ethers.utils.isAddress(implementationAddress) || + !ethers.utils.isAddress(rollupAddress) || + !ethers.utils.isAddress(owner) || + !(minimumStake > 0) || + !(challengeDeposit > 0) || + !(rewardPercentage > 0 && rewardPercentage <= 100) || + !Array.isArray(plannedSubmitters) || + plannedSubmitters.some((address) => !ethers.utils.isAddress(address)) + ) { + return "invalid Submitter install configuration"; + } + + const proxy = await hre.ethers.getContractAt( + ContractFactoryName.DefaultProxyInterface, + proxyAddress, + deployer + ); + const currentImplementation = await proxy.implementation(); + if (currentImplementation.toLowerCase() !== implementationAddress.toLowerCase()) { + if (currentImplementation.toLowerCase() !== emptyImplementation.toLowerCase()) { + return `Submitter proxy has unexpected implementation ${currentImplementation}`; + } + const factory = await hre.ethers.getContractFactory(ContractFactoryName.Submitter); + const initializer = factory.interface.encodeFunctionData("initialize", [ + owner, + rollupAddress, + hre.ethers.utils.parseEther(minimumStake.toString()), + hre.ethers.utils.parseEther(challengeDeposit.toString()), + rewardPercentage, + ]); + const response = await proxy.upgradeToAndCall(implementationAddress, initializer); + await response.wait(); + } + + // A transparent proxy admin cannot call business getters. Use a non-admin eth_call sender. + const reader = hre.ethers.Wallet.createRandom().connect(hre.ethers.provider); + const submitter = await hre.ethers.getContractAt(ContractFactoryName.Submitter, proxyAddress, reader); + if ((await submitter.owner()).toLowerCase() !== owner.toLowerCase()) { + return "Submitter owner verification failed"; + } + if ((await submitter.rollupContract()).toLowerCase() !== rollupAddress.toLowerCase()) { + return "Submitter rollup binding verification failed"; + } + if (!(await submitter.minimumStake()).eq(hre.ethers.utils.parseEther(minimumStake.toString()))) { + return "Submitter minimum stake verification failed"; + } + if (!(await submitter.challengeDeposit()).eq(hre.ethers.utils.parseEther(challengeDeposit.toString()))) { + return "Submitter challenge deposit verification failed"; + } + if (!(await submitter.rewardPercentage()).eq(rewardPercentage)) { + return "Submitter reward percentage verification failed"; + } + for (const account of plannedSubmitters) { + if ((await submitter.registered(account)) || !(await submitter.stakeOf(account)).isZero()) { + return `Submitter ${account} must remain unregistered and unstaked before Rollup cutover`; + } + } + + const rawImplementation = await hre.ethers.provider.getStorageAt(proxyAddress, IMPLEMENTATION_SLOT); + const implementationInSlot = ethers.utils.getAddress(ethers.utils.hexDataSlice(rawImplementation, 12)); + if (implementationInSlot.toLowerCase() !== implementationAddress.toLowerCase()) { + return "Submitter EIP-1967 implementation slot verification failed"; + } + const implementationCode = await hre.ethers.provider.getCode(implementationAddress); + if (implementationCode === "0x") return "Submitter implementation has no code"; + const blockNumber = await hre.ethers.provider.getBlockNumber(); + return storage(path, ImplStorageName.SubmitterInstallStorageName, proxyAddress.toLowerCase(), blockNumber, { + implementationSlot: IMPLEMENTATION_SLOT, + implementation: implementationAddress.toLowerCase(), + implementationCodeHash: ethers.utils.keccak256(implementationCode), + rollupContract: rollupAddress.toLowerCase(), + owner: owner.toLowerCase(), + }); + } catch (error) { + console.error("Submitter install failed", error); + return error instanceof Error ? error.message : "Submitter install failed"; + } +}; + +export default SubmitterInstall; diff --git a/contracts/deploy/016-RollupInit.ts b/contracts/deploy/016-RollupInit.ts index 82036f186..9043d2b34 100644 --- a/contracts/deploy/016-RollupInit.ts +++ b/contracts/deploy/016-RollupInit.ts @@ -23,7 +23,7 @@ export const RollupInit = async ( // Load the contracts we need to interact with. const ZkEvmVerifierV1Address = getContractAddressByName(path, ImplStorageName.ZkEvmVerifierV1StorageName) const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName(path, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName) - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const SubmitterProxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName) // Rollup config const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) @@ -60,7 +60,7 @@ export const RollupInit = async ( if (!ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || !ethers.utils.isAddress(MultipleVersionRollupVerifierContract.address) - || !ethers.utils.isAddress(L1StakingProxyAddress) + || !ethers.utils.isAddress(SubmitterProxyAddress) ) { console.error('please check your address') @@ -70,7 +70,7 @@ export const RollupInit = async ( await IRollupProxy.upgradeToAndCall( RollupImplAddress, RollupFactory.interface.encodeFunctionData('initialize', [ - L1StakingProxyAddress, + SubmitterProxyAddress, L1MessageQueueWithGasPriceOracleProxyAddress, MultipleVersionRollupVerifierContract.address, finalizationPeriodSeconds, @@ -97,8 +97,8 @@ export const RollupInit = async ( ) await assertContractVariable( contractTmp, - 'l1StakingContract', - L1StakingProxyAddress + 'submitterContract', + SubmitterProxyAddress ) await assertContractVariable( contractTmp, diff --git a/contracts/deploy/018-StakingInit.ts b/contracts/deploy/018-StakingInit.ts deleted file mode 100644 index 5cf151a42..000000000 --- a/contracts/deploy/018-StakingInit.ts +++ /dev/null @@ -1,128 +0,0 @@ -import "@nomiclabs/hardhat-web3"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; - -import { - HardhatRuntimeEnvironment -} from 'hardhat/types'; -import { assertContractVariable, getContractAddressByName, awaitCondition } from "../src/deploy-utils"; -import { ethers } from 'ethers' - -import { - ImplStorageName, - ProxyStorageName, - ContractFactoryName, -} from "../src/types" - -export const StakingInit = async ( - hre: HardhatRuntimeEnvironment, - path: string, - deployer: any, - configTmp: any -): Promise => { - // Load the contracts we need to interact with. - const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) - - // Staking config - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingImplAddress = getContractAddressByName(path, ImplStorageName.L1StakingStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - - const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) - if ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() !== L1StakingImplAddress.toLocaleLowerCase() - ) { - console.log('Upgrading the Staking proxy...') - const admin: string = configTmp.contractAdmin - const stakingChallengerRewardPercentage: number = configTmp.stakingChallengerRewardPercentage - const limit: number = configTmp.stakingMinDeposit - const challengeDeposit: number = configTmp.stakingChallengeDeposit - const lock: number = configTmp.stakingLockNumber - const gasLimitAdd: number = configTmp.stakingCrossChainGaslimitAdd - const gasLimitRemove: number = configTmp.stakingCrossChainGaslimitRemove - - if (!ethers.utils.isAddress(admin) - || lock <= 0 - || limit <= 0 - || challengeDeposit <= 0 - || gasLimitAdd <= 0 - || gasLimitRemove <= 0 - || stakingChallengerRewardPercentage > 100 - || stakingChallengerRewardPercentage <= 0 - ) { - console.error('please check your address') - return '' - } - - // Upgrade and initialize the proxy. - await IL1StakingProxy.upgradeToAndCall( - L1StakingImplAddress, - L1StakingFactory.interface.encodeFunctionData('initialize', [ - RollupProxyAddress, - hre.ethers.utils.parseEther(limit.toString()), - hre.ethers.utils.parseEther(challengeDeposit.toString()), - lock.toString(), - stakingChallengerRewardPercentage, - gasLimitAdd, - gasLimitRemove, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - - const contractTmp = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - deployer, - ) - - await assertContractVariable( - contractTmp, - 'rollupContract', - RollupProxyAddress - ) - await assertContractVariable( - contractTmp, - 'rewardPercentage', - stakingChallengerRewardPercentage - ) - await assertContractVariable( - contractTmp, - 'stakingValue', - hre.ethers.utils.parseEther(limit.toString()) - ) - await assertContractVariable( - contractTmp, - 'withdrawalLockBlocks', - lock.toString() - ) - await assertContractVariable( - contractTmp, - 'gasLimitAddStaker', - gasLimitAdd - ) - await assertContractVariable( - contractTmp, - 'gasLimitRemoveStakers', - gasLimitRemove - ) - await assertContractVariable( - contractTmp, - 'owner', - await deployer.getAddress(), - ) - // Wait for the transaction to execute properly. - console.log('StakingProxy upgrade success') - } - return '' -} - -export default StakingInit diff --git a/contracts/deploy/019-AdminTransfer.ts b/contracts/deploy/019-AdminTransfer.ts index a0cd1b58a..491248494 100644 --- a/contracts/deploy/019-AdminTransfer.ts +++ b/contracts/deploy/019-AdminTransfer.ts @@ -108,7 +108,7 @@ export const AdminTransferConcurrently = async ( const contractsToChange = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.L1StakingProxyStorageName, + ProxyStorageName.SubmitterProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, // Added L1Sequencer ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, @@ -159,7 +159,7 @@ export const AdminTransfer = async ( const L1MessageQueueWithGasPriceOracleProxyStorageName = ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName + const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -187,9 +187,9 @@ export const AdminTransfer = async ( return err } - // ************************ staking contracts admin change ************************ - // StakingProxy admin change - err = await AdminTransferByProxyStorageName(hre, path, deployer, L1StakingProxyStorageName) + // ************************ batch submitter contract admin change ************************ + // SubmitterProxy admin change + err = await AdminTransferByProxyStorageName(hre, path, deployer, SubmitterProxyStorageName) if (err != '') { return err } diff --git a/contracts/deploy/020-ContractInit.ts b/contracts/deploy/020-ContractInit.ts index 96bf3637b..22ed49663 100644 --- a/contracts/deploy/020-ContractInit.ts +++ b/contracts/deploy/020-ContractInit.ts @@ -31,20 +31,6 @@ export const ContractInit = async ( let rec = await res.wait() console.log(`set base fee ${rec.status === 1} setL2BaseFee(${await GasPriceOracle.l2BaseFee()}) gwei`) - const WhitelistImplAddress = getContractAddressByName(path, ImplStorageName.Whitelist) - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) - let addList = [L1StakingProxyAddress] - res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) - rec = await res.wait() - for (let i = 0; i < addList.length; i++) { - let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) - if (res != true) { - console.error('whitelist check failed') - return '' - } - } - console.log(`add ${addList} to whitelist success`) } // ------------------ rollup init ----------------- @@ -54,14 +40,11 @@ export const ContractInit = async ( // import genesis batch const batchHeader: string = config.batchHeader - // submitter and challenger - const submitter: string = config.rollupProposer + // challenger const challenger: string = config.rollupChallenger const rollupDelayPeriod: number = config.rollupDelayPeriod - if (!ethers.utils.isAddress(submitter) - || !ethers.utils.isAddress(challenger) - ) { + if (!ethers.utils.isAddress(challenger)) { console.error('please check your address') return '' } @@ -85,29 +68,6 @@ export const ContractInit = async ( console.log(`initialize3(%s) ${rec.status == 1 ? "success" : "failed"}`) } - // ------------------ staking init ----------------- - { - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) - const whiteListAdd = config.l2SequencerAddresses - console.log("Add sequencer address to white list ", config.l2SequencerAddresses) - // set sequencer to white list - await L1Staking.updateWhitelist(whiteListAdd, []) - for (let i = 0; i < config.l2SequencerAddresses.length; i++) { - // Wait for the transaction to execute properly. - await awaitCondition( - async () => { - return ( - await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true - ) - }, - 3000, - 1000 - ) - console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) - } - } - // ------------------ router init ----------------- { const L1WETHAddress = getContractAddressByName(path, ImplStorageName.WETH) diff --git a/contracts/deploy/021-StakingRegister.ts b/contracts/deploy/021-StakingRegister.ts deleted file mode 100644 index 9e69e0bf8..000000000 --- a/contracts/deploy/021-StakingRegister.ts +++ /dev/null @@ -1,57 +0,0 @@ -import "@nomiclabs/hardhat-web3"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; - -import { - HardhatRuntimeEnvironment -} from 'hardhat/types'; -import { getContractAddressByName, awaitCondition } from "../src/deploy-utils"; -import { ethers } from 'ethers' -import { - ProxyStorageName, - ContractFactoryName, -} from "../src/types" - -const two = BigInt(2) -const gwei = BigInt(1e9) -const eth = gwei * gwei - -export const StakingRegister = async ( - hre: HardhatRuntimeEnvironment, - path: string, - signer: any, - tmKey: string, - blsKey: string -): Promise => { - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - - const StakingProxyWithSigner = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - signer, - ) - - // just for devnet register value may set params to config - const response = await StakingProxyWithSigner.register(tmKey, blsKey, { - value: eth - }) - console.log(`Transaction hash (on L1): ${response.hash}`) - const receipt = await response.wait() - console.log('Transaction in L1 height', receipt.blockNumber) - - await awaitCondition( - async () => { - const sequencerInfo = (await StakingProxyWithSigner.stakers(signer.address)) - if (sequencerInfo && sequencerInfo.tmKey === tmKey) { - return true - } - return false - }, - 30000, - 1000 - ) - return '' -} - -export default StakingRegister \ No newline at end of file diff --git a/contracts/deploy/021-SubmitterRegister.ts b/contracts/deploy/021-SubmitterRegister.ts new file mode 100644 index 000000000..76a71b524 --- /dev/null +++ b/contracts/deploy/021-SubmitterRegister.ts @@ -0,0 +1,38 @@ +import "@nomiclabs/hardhat-ethers"; + +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ethers } from "ethers"; + +import { getContractAddressByName } from "../src/deploy-utils"; +import { ContractFactoryName, ProxyStorageName } from "../src/types"; + +export const SubmitterRegister = async ( + hre: HardhatRuntimeEnvironment, + path: string, + ownerSigner: any, + submitterSigner: any +): Promise => { + const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); + if (!ethers.utils.isAddress(proxyAddress)) return "invalid Submitter proxy address"; + + const ownerView = await hre.ethers.getContractAt(ContractFactoryName.Submitter, proxyAddress, ownerSigner); + const account = await submitterSigner.getAddress(); + if ((await ownerView.owner()).toLowerCase() !== (await ownerSigner.getAddress()).toLowerCase()) { + return "registration signer is not Submitter owner"; + } + if (!(await ownerView.registered(account))) { + await (await ownerView.addSubmitter(account)).wait(); + } + + const submitterView = ownerView.connect(submitterSigner); + const minimumStake = await submitterView.minimumStake(); + const currentStake = await submitterView.stakeOf(account); + if (currentStake.lt(minimumStake)) { + await (await submitterView.stake({ value: minimumStake.sub(currentStake) })).wait(); + } + if (!(await submitterView.isActive(account))) return "Submitter did not become active"; + console.log(`Submitter ${account} registered and active with stake ${await submitterView.stakeOf(account)}`); + return ""; +}; + +export default SubmitterRegister; diff --git a/contracts/deploy/index.ts b/contracts/deploy/index.ts index a30ab90fb..b0d41da05 100644 --- a/contracts/deploy/index.ts +++ b/contracts/deploy/index.ts @@ -3,13 +3,13 @@ import deployEmptyContract from './011-EmptyContract' import {deployContractProxies,deployContractProxiesConcurrently} from './013-DeployProxys' import deployZkEvmVerifierV1 from './012-Verifier' import {deployContractImpls, deployContractImplsConcurrently} from './014-DeployImpls' +import SubmitterInstall from './015-SubmitterInstall' import MessengerInit from './015-MessengerInit' import RollupInit from './016-RollupInit' import GatewayInit from './017-GatewayInit' -import StakingInit from './018-StakingInit' import {AdminTransfer,AdminTransferByProxyStorageName, AdminTransferConcurrently} from './019-AdminTransfer' import ContractInit from './020-ContractInit' -import StakingRegister from './021-StakingRegister' +import SubmitterRegister from './021-SubmitterRegister' import SequencerInit from './022-SequencerInit' @@ -21,14 +21,14 @@ export { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, + SubmitterInstall, MessengerInit, RollupInit, GatewayInit, - StakingInit, AdminTransfer, AdminTransferByProxyStorageName, AdminTransferConcurrently, ContractInit, - StakingRegister, + SubmitterRegister, SequencerInit -} \ No newline at end of file +} diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index c60bf6ec7..af8adc51b 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -9,13 +9,11 @@ import fs from "fs" import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from "hardhat/builtin-tasks/task-names"; import { subtask } from "hardhat/config"; - import "./tasks/deploy" import "./tasks/overflow_test" import "./tasks/check" import "./tasks/query" import "./tasks/proxy_upgrade" -import "./tasks/staking_upgrade" import "./tasks/verifier_upgrade" import "./tasks/token_deploy" import "./tasks/mainnet_upgrade" @@ -51,7 +49,9 @@ module.exports = { abiExporter: { path: './abi', runOnCompile: true, - clear: true, + // The immutable pre-submitter and legacy retirement ABIs live under abi/archive. + // Never let a routine current-ABI export erase those cutover artifacts. + clear: false, }, bytecodeExporter: { path: './data', @@ -156,4 +156,4 @@ module.exports = { artifacts: "./artifacts", deployConfig: './src/deploy-config', } -} \ No newline at end of file +} diff --git a/contracts/integration-test/retire-l1-staking.spec.ts b/contracts/integration-test/retire-l1-staking.spec.ts new file mode 100644 index 000000000..f7eabd5b0 --- /dev/null +++ b/contracts/integration-test/retire-l1-staking.spec.ts @@ -0,0 +1,122 @@ +import { expect } from "chai"; +import { BigNumber, ethers } from "ethers"; + +import { + ReplayEvent, + RetirementManifest, + rebuildLegacyState, + retirementBlockers, + verifyExecutePreconditions, +} from "../scripts/retire-l1-staking"; + +const alice = "0x00000000000000000000000000000000000000a1"; +const bob = "0x00000000000000000000000000000000000000b2"; + +function event( + blockNumber: number, + blockHash: string, + name: string, + args: Record, + logIndex = 0 +): ReplayEvent { + return { + blockNumber, + blockHash, + transactionHash: `0x${blockNumber.toString(16).padStart(64, "0")}`, + logIndex, + name, + args, + }; +} + +function manifest(): RetirementManifest { + return { + version: 1, + legacy: { + proxy: "0x0000000000000000000000000000000000000100", + deployBlock: 1, + deployBlockHash: "0x01", + proxyAdminIsDedicated: false, + burnAdmin: "0x000000000000000000000000000000000000dEaD", + }, + retirement: { confirmations: 1, stakingValue: "100", treasury: alice }, + snapshot: { + chainId: 1, + safeHead: 10, + safeHeadHash: "0x10", + stakingValue: "100", + contractBalance: "0", + expectedLiabilities: "0", + unexplainedBalance: "0", + slashRemaining: "0", + owner: alice, + activeStakers: [], + }, + candidates: [], + canonicalEventIds: [], + checkpoints: [], + relays: [], + operations: [], + }; +} + +describe("legacy L1Staking retirement planning", () => { + it("aborts when stakingValue changes during the withdrawal window", () => { + const plan = manifest(); + expect(() => verifyExecutePreconditions(plan, { stakingValue: BigNumber.from(101) })).to.throw( + "stakingValue changed during retirement" + ); + }); + + it("rebuilds ever-whitelisted state from the canonical branch after a short reorg", () => { + const orphanHash = `0x${"aa".repeat(32)}`; + const canonicalHash = `0x${"bb".repeat(32)}`; + const events = [ + event(10, orphanHash, "WhitelistUpdated", { add: [alice], remove: [] }), + event(10, canonicalHash, "WhitelistUpdated", { add: [bob], remove: [] }), + event(10, canonicalHash, "Registered", { addr: bob }, 1), + event(10, canonicalHash, "Withdrawn", { addr: bob }, 2), + event(10, canonicalHash, "StakersRemoved", { stakers: [bob] }, 3), + ]; + + const rebuilt = rebuildLegacyState(events, { 10: canonicalHash }); + expect(rebuilt.candidates.map((candidate) => candidate.address)).to.deep.equal([ethers.utils.getAddress(bob)]); + expect(rebuilt.candidates[0].everRegistered).to.equal(true); + expect(rebuilt.candidates[0].withdrawn).to.equal(true); + expect(rebuilt.candidates[0].removed).to.equal(true); + expect(rebuilt.canonicalEventIds).to.have.length(4); + }); + + it("blocks owner/admin retirement until whitelist, withdrawals, relays, and admin scope are clean", () => { + const plan = manifest(); + plan.candidates = [ + { + address: alice, + everRegistered: true, + withdrawn: true, + claimed: false, + slashed: false, + removed: true, + currentWhitelist: true, + currentActive: false, + withdrawalUnlockBlock: "12", + }, + ]; + plan.relays = [ + { + messageHash: "0x01", + addresses: [alice], + transactionHash: "0x02", + blockHash: "0x03", + success: false, + canonical: false, + }, + ]; + expect(retirementBlockers(plan)).to.include.members([ + `${alice}: whitelist still enabled`, + `${alice}: withdrawal still pending`, + "0x01: removeStakers relay incomplete", + "legacy proxy admin is not confirmed dedicated", + ]); + }); +}); diff --git a/contracts/integration-test/submitter-deploy.spec.ts b/contracts/integration-test/submitter-deploy.spec.ts new file mode 100644 index 000000000..b713ea961 --- /dev/null +++ b/contracts/integration-test/submitter-deploy.spec.ts @@ -0,0 +1,72 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; + +const EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"; + +describe("Submitter deployment order", () => { + it("installs and initializes Submitter before Rollup and admin transfer", async () => { + const [proxyAdminSigner, submitterOwner, other] = await ethers.getSigners(); + const empty = await (await ethers.getContractFactory("EmptyContract")).deploy(); + const proxyFactory = await ethers.getContractFactory("TransparentUpgradeableProxy"); + const rollupProxy = await proxyFactory.deploy(empty.address, proxyAdminSigner.address, "0x"); + const submitterProxy = await proxyFactory.deploy(empty.address, proxyAdminSigner.address, "0x"); + const submitterImpl = await (await ethers.getContractFactory("Submitter")).deploy(); + const rollupImpl = await (await ethers.getContractFactory("Rollup")).deploy(53077); + + const proxyAdminView = await ethers.getContractAt( + "ITransparentUpgradeableProxy", + submitterProxy.address, + proxyAdminSigner + ); + const submitterFactory = await ethers.getContractFactory("Submitter"); + await proxyAdminView.upgradeToAndCall( + submitterImpl.address, + submitterFactory.interface.encodeFunctionData("initialize", [ + submitterOwner.address, + rollupProxy.address, + ethers.utils.parseEther("1"), + ethers.utils.parseEther("1"), + 20, + ]) + ); + expect(await proxyAdminView.implementation()).to.equal(submitterImpl.address); + + const submitter = await ethers.getContractAt("Submitter", submitterProxy.address, submitterOwner); + expect(await submitter.owner()).to.equal(submitterOwner.address); + expect(await submitter.rollupContract()).to.equal(rollupProxy.address); + await expect( + submitter.initialize( + submitterOwner.address, + rollupProxy.address, + ethers.utils.parseEther("1"), + ethers.utils.parseEther("1"), + 20 + ) + ).to.be.revertedWith("Initializable: contract is already initialized"); + + const rollupProxyAdminView = await ethers.getContractAt( + "ITransparentUpgradeableProxy", + rollupProxy.address, + proxyAdminSigner + ); + const rollupFactory = await ethers.getContractFactory("Rollup"); + await rollupProxyAdminView.upgradeToAndCall( + rollupImpl.address, + rollupFactory.interface.encodeFunctionData("initialize", [ + submitterProxy.address, + other.address, + other.address, + 10, + 100, + 70, + ]) + ); + const rollup = await ethers.getContractAt("Rollup", rollupProxy.address, submitterOwner); + expect(await rollup.submitterContract()).to.equal(submitterProxy.address); + + const proxyAdmin = await (await ethers.getContractFactory("ProxyAdmin")).deploy(); + await proxyAdminView.changeAdmin(proxyAdmin.address); + const rawAdmin = await ethers.provider.getStorageAt(submitterProxy.address, EIP1967_ADMIN_SLOT); + expect(ethers.utils.getAddress(ethers.utils.hexDataSlice(rawAdmin, 12))).to.equal(proxyAdmin.address); + }); +}); diff --git a/contracts/ops/legacy-l1-staking-retirement.example.json b/contracts/ops/legacy-l1-staking-retirement.example.json new file mode 100644 index 000000000..c338e09f9 --- /dev/null +++ b/contracts/ops/legacy-l1-staking-retirement.example.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "legacy": { + "proxy": "0x0000000000000000000000000000000000000000", + "deployBlock": 0, + "proxyAdminIsDedicated": false, + "burnAdmin": "0x000000000000000000000000000000000000dEaD" + }, + "retirement": { + "confirmations": 64, + "treasury": "0x0000000000000000000000000000000000000000" + }, + "candidates": [], + "canonicalEventIds": [], + "checkpoints": [], + "relays": [], + "operations": [] +} diff --git a/contracts/scripts/retire-l1-staking.ts b/contracts/scripts/retire-l1-staking.ts new file mode 100644 index 000000000..e3371c1e6 --- /dev/null +++ b/contracts/scripts/retire-l1-staking.ts @@ -0,0 +1,664 @@ +import { createHash } from "crypto"; +import fs from "fs"; +import path from "path"; + +import { BigNumber, Contract, Wallet, ethers } from "ethers"; + +const ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"; +const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; +const ZERO_ADDRESS = ethers.constants.AddressZero; + +export type RetirementMode = "plan" | "dry-run" | "execute" | "verify"; + +export interface ReplayEvent { + name: string; + args: Record; + blockNumber: number; + blockHash: string; + transactionHash: string; + logIndex: number; +} + +export interface CandidateState { + address: string; + firstEvent?: string; + lastEvent?: string; + everRegistered: boolean; + withdrawn: boolean; + claimed: boolean; + slashed: boolean; + removed: boolean; + currentWhitelist?: boolean; + currentActive?: boolean; + withdrawalUnlockBlock?: string; +} + +export interface RetirementOperation { + kind: "freeze" | "withdraw" | "claim" | "claim-slash" | "renounce-owner" | "burn-admin"; + actor: string; + target: string; + value: string; + data: string; + description: string; + nonce?: number; + expectedState: string[]; + txHash?: string; + receiptBlockHash?: string; +} + +export interface RelayEvidence { + messageHash: string; + addresses?: string[]; + transactionHash: string; + blockHash: string; + success: boolean; + canonical: boolean; +} + +export interface RetirementManifest { + version: number; + legacy: { + proxy: string; + implementation?: string; + deployBlock: number; + deployBlockHash?: string; + proxyAdmin?: string; + proxyAdminOwner?: string; + proxyAdminIsDedicated: boolean; + burnAdmin: string; + }; + retirement: { + confirmations: number; + stakingValue?: string; + treasury: string; + }; + snapshot?: { + chainId: number; + safeHead: number; + safeHeadHash: string; + stakingValue: string; + contractBalance: string; + expectedLiabilities: string; + unexplainedBalance: string; + slashRemaining: string; + owner: string; + activeStakers: string[]; + }; + candidates: CandidateState[]; + canonicalEventIds: string[]; + checkpoints: Array<{ blockNumber: number; blockHash: string }>; + relays: RelayEvidence[]; + operations: RetirementOperation[]; + verifiedAt?: string; +} + +function normalizeAddress(value: string): string { + return ethers.utils.getAddress(value); +} + +function eventId(event: ReplayEvent): string { + return `${event.blockHash}:${event.transactionHash}:${event.logIndex}`; +} + +function eventAddresses(value: unknown): string[] { + if (!Array.isArray(value)) return []; + return value.filter((item): item is string => typeof item === "string").map(normalizeAddress); +} + +/** + * Rebuilds state from scratch against canonical block hashes. Rebuilding instead of appending + * means orphaned tip events disappear automatically after an L1 reorg. + */ +export function rebuildLegacyState( + events: ReplayEvent[], + canonicalBlockHashes: Record +): { candidates: CandidateState[]; canonicalEventIds: string[] } { + const candidates = new Map(); + const canonicalEventIds: string[] = []; + + const get = (address: string, identity: string): CandidateState => { + const normalized = normalizeAddress(address); + const key = normalized.toLowerCase(); + let state = candidates.get(key); + if (!state) { + state = { + address: normalized, + firstEvent: identity, + lastEvent: identity, + everRegistered: false, + withdrawn: false, + claimed: false, + slashed: false, + removed: false, + }; + candidates.set(key, state); + } + state.lastEvent = identity; + return state; + }; + + for (const event of [...events].sort((a, b) => a.blockNumber - b.blockNumber || a.logIndex - b.logIndex)) { + const canonicalHash = canonicalBlockHashes[event.blockNumber]; + if (!canonicalHash || canonicalHash.toLowerCase() !== event.blockHash.toLowerCase()) continue; + const identity = eventId(event); + canonicalEventIds.push(identity); + + if (event.name === "WhitelistUpdated") { + for (const address of eventAddresses(event.args.add)) get(address, identity); + for (const address of eventAddresses(event.args.remove)) get(address, identity); + } else if (event.name === "Registered") { + const state = get(String(event.args.addr), identity); + state.everRegistered = true; + state.withdrawn = false; + state.claimed = false; + state.slashed = false; + state.removed = false; + } else if (event.name === "Withdrawn") { + get(String(event.args.addr), identity).withdrawn = true; + } else if (event.name === "Claimed") { + const state = get(String(event.args.staker), identity); + state.claimed = true; + state.withdrawn = false; + } else if (event.name === "Slashed") { + for (const address of eventAddresses(event.args.stakers)) { + const state = get(address, identity); + state.slashed = true; + state.removed = true; + } + } else if (event.name === "StakersRemoved") { + for (const address of eventAddresses(event.args.stakers)) get(address, identity).removed = true; + } + } + + return { + candidates: [...candidates.values()].sort((a, b) => a.address.localeCompare(b.address)), + canonicalEventIds, + }; +} + +export function verifyExecutePreconditions( + manifest: RetirementManifest, + current: { stakingValue: BigNumber | string; deployBlockHash?: string } +): void { + if (!manifest.retirement.stakingValue) throw new Error("retirement stakingValue snapshot missing"); + if (!BigNumber.from(current.stakingValue).eq(manifest.retirement.stakingValue)) { + throw new Error("stakingValue changed during retirement"); + } + if ( + manifest.legacy.deployBlockHash && + current.deployBlockHash && + manifest.legacy.deployBlockHash.toLowerCase() !== current.deployBlockHash.toLowerCase() + ) { + throw new Error("legacy deployment block is no longer canonical"); + } +} + +export function retirementBlockers(manifest: RetirementManifest): string[] { + const blockers: string[] = []; + if (!manifest.snapshot) return ["snapshot missing"]; + for (const candidate of manifest.candidates) { + if (candidate.currentWhitelist) blockers.push(`${candidate.address}: whitelist still enabled`); + if (candidate.currentActive) blockers.push(`${candidate.address}: staker still active`); + if (BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0)) { + blockers.push(`${candidate.address}: withdrawal still pending`); + } + } + if (!BigNumber.from(manifest.snapshot.slashRemaining).isZero()) blockers.push("slashRemaining is nonzero"); + if (!BigNumber.from(manifest.snapshot.contractBalance).isZero()) blockers.push("legacy contract balance is nonzero"); + for (const relay of manifest.relays) { + if (!relay.success || !relay.canonical) blockers.push(`${relay.messageHash}: removeStakers relay incomplete`); + } + for (const candidate of manifest.candidates.filter( + (item) => item.removed || item.withdrawn || item.slashed + )) { + const covered = manifest.relays.some( + (relay) => + relay.success && + relay.canonical && + (relay.addresses || []).some( + (address) => address.toLowerCase() === candidate.address.toLowerCase() + ) + ); + if (!covered) blockers.push(`${candidate.address}: canonical removeStakers relay evidence missing`); + } + if (!manifest.legacy.proxyAdminIsDedicated) blockers.push("legacy proxy admin is not confirmed dedicated"); + return blockers; +} + +function archivedAbiPath(): string { + return path.resolve(__dirname, "../abi/archive/legacy-l1-staking/L1Staking.json"); +} + +function loadFrozenAbi(): unknown[] { + const abiPath = archivedAbiPath(); + const archiveManifestPath = path.resolve(__dirname, "../abi/archive/manifest.json"); + if (!fs.existsSync(abiPath) || !fs.existsSync(archiveManifestPath)) { + throw new Error("frozen legacy L1Staking ABI archive is missing"); + } + const raw = fs.readFileSync(abiPath); + const archiveManifest = JSON.parse(fs.readFileSync(archiveManifestPath, "utf8")); + const expected = archiveManifest.artifacts?.["legacy-l1-staking/L1Staking.json"]; + const actual = createHash("sha256").update(raw).digest("hex"); + if (!expected || actual !== expected) throw new Error("frozen legacy L1Staking ABI hash mismatch"); + return JSON.parse(raw.toString("utf8")); +} + +function addressFromSlot(raw: string): string { + return normalizeAddress(ethers.utils.hexDataSlice(raw, 12)); +} + +async function collectCanonicalEvents( + provider: ethers.providers.Provider, + contractAddress: string, + deployBlock: number, + safeHead: number, + abi: unknown[] +): Promise<{ events: ReplayEvent[]; hashes: Record; checkpoints: RetirementManifest["checkpoints"] }> { + const iface = new ethers.utils.Interface(abi); + const logs = await provider.getLogs({ address: contractAddress, fromBlock: deployBlock, toBlock: safeHead }); + const blockNumbers = [...new Set([deployBlock, safeHead, ...logs.map((log) => log.blockNumber)])]; + const blocks = await Promise.all(blockNumbers.map((number) => provider.getBlock(number))); + const hashes: Record = {}; + const checkpoints: RetirementManifest["checkpoints"] = []; + for (const block of blocks) { + if (!block) throw new Error("canonical block lookup failed"); + hashes[block.number] = block.hash; + checkpoints.push({ blockNumber: block.number, blockHash: block.hash }); + } + + const events: ReplayEvent[] = []; + for (const log of logs) { + try { + const parsed = iface.parseLog(log); + if (!["WhitelistUpdated", "Registered", "Withdrawn", "Claimed", "Slashed", "StakersRemoved"].includes(parsed.name)) { + continue; + } + const args: Record = {}; + for (const [key, value] of Object.entries(parsed.args)) { + if (!/^\d+$/.test(key)) args[key] = value; + } + events.push({ + name: parsed.name, + args, + blockNumber: log.blockNumber, + blockHash: log.blockHash, + transactionHash: log.transactionHash, + logIndex: log.logIndex, + }); + } catch { + // The proxy may emit unrelated proxy-admin events; the frozen business ABI does not parse them. + } + } + return { events, hashes, checkpoints }; +} + +async function refreshManifest( + provider: ethers.providers.JsonRpcProvider, + manifest: RetirementManifest, + abi: unknown[] +): Promise { + const latest = await provider.getBlockNumber(); + const safeHead = latest - manifest.retirement.confirmations; + if (safeHead < manifest.legacy.deployBlock) throw new Error("safe head precedes legacy deployment"); + const chain = await provider.getNetwork(); + const contract = new Contract(manifest.legacy.proxy, abi, provider); + const replay = await collectCanonicalEvents(provider, manifest.legacy.proxy, manifest.legacy.deployBlock, safeHead, abi); + const rebuilt = rebuildLegacyState(replay.events, replay.hashes); + const activeStakers: string[] = (await contract.getActiveStakers({ blockTag: safeHead })).map(normalizeAddress); + const candidateMap = new Map(rebuilt.candidates.map((candidate) => [candidate.address.toLowerCase(), candidate])); + for (const address of activeStakers) { + if (!candidateMap.has(address.toLowerCase())) { + candidateMap.set(address.toLowerCase(), { + address, + everRegistered: true, + withdrawn: false, + claimed: false, + slashed: false, + removed: false, + }); + } + } + const candidates = [...candidateMap.values()].sort((a, b) => a.address.localeCompare(b.address)); + for (const candidate of candidates) { + const [whitelist, active, withdrawal] = await Promise.all([ + contract.whitelist(candidate.address, { blockTag: safeHead }), + contract.isActiveStaker(candidate.address, { blockTag: safeHead }), + contract.withdrawals(candidate.address, { blockTag: safeHead }), + ]); + candidate.currentWhitelist = whitelist; + candidate.currentActive = active; + candidate.withdrawalUnlockBlock = withdrawal.toString(); + } + + const [stakingValue, slashRemaining, owner, balance] = await Promise.all([ + contract.stakingValue({ blockTag: safeHead }), + contract.slashRemaining({ blockTag: safeHead }), + contract.owner({ blockTag: safeHead }), + provider.getBalance(manifest.legacy.proxy, safeHead), + ]); + const liabilityCount = candidates.filter( + (candidate) => candidate.currentActive || BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0) + ).length; + const expectedLiabilities = stakingValue.mul(liabilityCount).add(slashRemaining); + const unexplainedBalance = balance.gt(expectedLiabilities) ? balance.sub(expectedLiabilities) : BigNumber.from(0); + const safeBlock = await provider.getBlock(safeHead); + const deployBlock = await provider.getBlock(manifest.legacy.deployBlock); + if (!safeBlock || !deployBlock) throw new Error("snapshot block lookup failed"); + + const rawAdmin = await provider.getStorageAt(manifest.legacy.proxy, ADMIN_SLOT, safeHead); + const rawImplementation = await provider.getStorageAt(manifest.legacy.proxy, IMPLEMENTATION_SLOT, safeHead); + manifest.legacy.proxyAdmin = addressFromSlot(rawAdmin); + manifest.legacy.implementation = addressFromSlot(rawImplementation); + manifest.legacy.deployBlockHash = deployBlock.hash; + if (!manifest.retirement.stakingValue) manifest.retirement.stakingValue = stakingValue.toString(); + verifyExecutePreconditions(manifest, { stakingValue, deployBlockHash: deployBlock.hash }); + + manifest.snapshot = { + chainId: chain.chainId, + safeHead, + safeHeadHash: safeBlock.hash, + stakingValue: stakingValue.toString(), + contractBalance: balance.toString(), + expectedLiabilities: expectedLiabilities.toString(), + unexplainedBalance: unexplainedBalance.toString(), + slashRemaining: slashRemaining.toString(), + owner: normalizeAddress(owner), + activeStakers, + }; + manifest.candidates = candidates; + manifest.canonicalEventIds = rebuilt.canonicalEventIds; + manifest.checkpoints = replay.checkpoints; + manifest.operations = await buildOperations(provider, contract, manifest, abi); + return manifest; +} + +async function buildOperations( + provider: ethers.providers.Provider, + contract: Contract, + manifest: RetirementManifest, + abi: unknown[] +): Promise { + if (!manifest.snapshot) throw new Error("snapshot missing"); + const iface = new ethers.utils.Interface(abi); + const owner = manifest.snapshot.owner; + const operations: RetirementOperation[] = []; + const whitelisted = manifest.candidates.filter((candidate) => candidate.currentWhitelist).map((candidate) => candidate.address); + if (whitelisted.length > 0) { + operations.push({ + kind: "freeze", + actor: owner, + target: manifest.legacy.proxy, + value: "0", + data: iface.encodeFunctionData("updateWhitelist", [[], whitelisted]), + description: `remove ${whitelisted.length} canonical ever-whitelisted address(es) from whitelist`, + expectedState: whitelisted.map((address) => `whitelist(${address}) == false`), + }); + } + for (const candidate of manifest.candidates) { + if (candidate.currentActive) { + operations.push({ + kind: "withdraw", + actor: candidate.address, + target: manifest.legacy.proxy, + value: "0", + data: iface.encodeFunctionData("withdraw"), + description: `withdraw legacy stake for ${candidate.address}`, + expectedState: [ + `isActiveStaker(${candidate.address}) == false`, + `withdrawals(${candidate.address}) > 0`, + ], + }); + } else if ( + BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0) && + BigNumber.from(candidate.withdrawalUnlockBlock || 0).lte(manifest.snapshot.safeHead) + ) { + operations.push({ + kind: "claim", + actor: candidate.address, + target: manifest.legacy.proxy, + value: "0", + data: iface.encodeFunctionData("claimWithdrawal", [candidate.address]), + description: `claim matured legacy withdrawal for ${candidate.address}`, + expectedState: [`withdrawals(${candidate.address}) == 0`], + }); + } + } + if (!BigNumber.from(manifest.snapshot.slashRemaining).isZero()) { + operations.push({ + kind: "claim-slash", + actor: owner, + target: manifest.legacy.proxy, + value: "0", + data: iface.encodeFunctionData("claimSlashRemaining", [manifest.retirement.treasury]), + description: "reconcile legacy slashRemaining to retirement treasury", + expectedState: ["slashRemaining() == 0"], + }); + } + + if (retirementBlockers(manifest).length === 0 && owner !== ZERO_ADDRESS) { + operations.push({ + kind: "renounce-owner", + actor: owner, + target: manifest.legacy.proxy, + value: "0", + data: iface.encodeFunctionData("renounceOwnership"), + description: "renounce legacy L1Staking business ownership", + expectedState: [`owner() == ${ZERO_ADDRESS}`], + }); + const admin = normalizeAddress(manifest.legacy.proxyAdmin || ZERO_ADDRESS); + if (admin === ZERO_ADDRESS || admin.toLowerCase() === manifest.legacy.burnAdmin.toLowerCase()) { + return assignOperationNonces(provider, operations); + } + const adminCode = await provider.getCode(admin); + if (adminCode === "0x") { + const proxyIface = new ethers.utils.Interface(["function changeAdmin(address newAdmin)"]); + operations.push({ + kind: "burn-admin", + actor: admin, + target: manifest.legacy.proxy, + value: "0", + data: proxyIface.encodeFunctionData("changeAdmin", [manifest.legacy.burnAdmin]), + description: "move the dedicated legacy proxy admin to the configured burn address", + expectedState: [`proxy admin == ${manifest.legacy.burnAdmin}`], + }); + } else { + const proxyAdmin = new Contract(admin, ["function owner() view returns (address)"], provider); + manifest.legacy.proxyAdminOwner = normalizeAddress( + await proxyAdmin.owner({ blockTag: manifest.snapshot.safeHead }) + ); + const proxyAdminIface = new ethers.utils.Interface([ + "function changeProxyAdmin(address proxy,address newAdmin)", + ]); + operations.push({ + kind: "burn-admin", + actor: manifest.legacy.proxyAdminOwner, + target: admin, + value: "0", + data: proxyAdminIface.encodeFunctionData("changeProxyAdmin", [ + manifest.legacy.proxy, + manifest.legacy.burnAdmin, + ]), + description: "detach only the legacy proxy from its confirmed-dedicated ProxyAdmin", + expectedState: [`proxy admin == ${manifest.legacy.burnAdmin}`], + }); + } + } + return assignOperationNonces(provider, operations); +} + +async function assignOperationNonces( + provider: ethers.providers.Provider, + operations: RetirementOperation[] +): Promise { + const nextNonce = new Map(); + for (const operation of operations) { + const actor = operation.actor.toLowerCase(); + let nonce = nextNonce.get(actor); + if (nonce === undefined) nonce = await provider.getTransactionCount(operation.actor, "pending"); + operation.nonce = nonce; + nextNonce.set(actor, nonce + 1); + } + return operations; +} + +function signerMap(provider: ethers.providers.JsonRpcProvider): Map { + const keys: string[] = JSON.parse(process.env.RETIRE_SIGNER_KEYS || "[]"); + const result = new Map(); + for (const key of keys) { + const wallet = new Wallet(key, provider); + result.set(wallet.address.toLowerCase(), wallet); + } + return result; +} + +async function executeOperations( + provider: ethers.providers.JsonRpcProvider, + manifest: RetirementManifest, + manifestPath: string, + abi: unknown[] +): Promise { + if (process.env.RETIRE_CONFIRM_EXECUTE !== "YES") { + throw new Error("execute mode requires RETIRE_CONFIRM_EXECUTE=YES"); + } + if (!manifest.snapshot) throw new Error("snapshot missing"); + const contract = new Contract(manifest.legacy.proxy, abi, provider); + const deployBlock = await provider.getBlock(manifest.legacy.deployBlock); + verifyExecutePreconditions(manifest, { + stakingValue: await contract.stakingValue(), + deployBlockHash: deployBlock?.hash, + }); + if (manifest.operations.some((operation) => operation.kind === "renounce-owner" || operation.kind === "burn-admin")) { + const [active, balance, slashRemaining] = await Promise.all([ + contract.getActiveStakers(), + provider.getBalance(manifest.legacy.proxy), + contract.slashRemaining(), + ]); + if (active.length > 0 || !balance.isZero() || !slashRemaining.isZero()) { + throw new Error("irreversible retirement gate changed after planning"); + } + for (const candidate of manifest.candidates) { + const [whitelisted, withdrawal] = await Promise.all([ + contract.whitelist(candidate.address), + contract.withdrawals(candidate.address), + ]); + if (whitelisted || !withdrawal.isZero()) { + throw new Error(`irreversible retirement gate changed for ${candidate.address}`); + } + } + } + const signers = signerMap(provider); + for (const operation of manifest.operations) { + if (!signers.has(operation.actor.toLowerCase())) { + throw new Error(`missing signer for ${operation.kind} actor ${operation.actor}`); + } + if (!Number.isSafeInteger(operation.nonce) || operation.nonce! < 0) { + throw new Error(`missing deterministic nonce for ${operation.kind} actor ${operation.actor}`); + } + } + // Resolve every actor and nonce before broadcasting so execution never partially applies a stale plan. + const firstNonceByActor = new Map(); + for (const operation of manifest.operations) { + const actor = operation.actor.toLowerCase(); + if (!firstNonceByActor.has(actor)) firstNonceByActor.set(actor, operation.nonce!); + } + for (const [actor, nonce] of firstNonceByActor) { + const current = await provider.getTransactionCount(actor, "pending"); + if (current !== nonce) throw new Error(`planned nonce changed for ${actor}: expected ${nonce}, got ${current}`); + } + for (const operation of manifest.operations) { + const signer = signers.get(operation.actor.toLowerCase())!; + const response = await signer.sendTransaction({ + to: operation.target, + data: operation.data, + value: BigNumber.from(operation.value), + nonce: operation.nonce, + }); + const receipt = await response.wait(); + if (receipt.status !== 1) throw new Error(`${operation.kind} transaction failed`); + operation.txHash = receipt.transactionHash; + operation.receiptBlockHash = receipt.blockHash; + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); + } +} + +async function dryRunOperations( + provider: ethers.providers.JsonRpcProvider, + manifest: RetirementManifest +): Promise { + if (!manifest.snapshot) throw new Error("snapshot missing"); + for (const operation of manifest.operations) { + try { + await provider.call( + { + from: operation.actor, + to: operation.target, + data: operation.data, + value: BigNumber.from(operation.value), + }, + manifest.snapshot.safeHead + ); + } catch (error) { + throw new Error( + `dry-run simulation failed for ${operation.kind} (${operation.description}): ${ + error instanceof Error ? error.message : String(error) + }` + ); + } + } +} + +async function verifyRelayEvidence( + provider: ethers.providers.Provider, + relays: RelayEvidence[] +): Promise { + for (const relay of relays) { + if (!relay.transactionHash) continue; + const receipt = await provider.getTransactionReceipt(relay.transactionHash); + relay.success = Boolean(receipt && receipt.status === 1); + relay.canonical = Boolean(receipt && receipt.blockHash.toLowerCase() === relay.blockHash.toLowerCase()); + } +} + +function parseArgs(): { mode: RetirementMode; manifestPath: string } { + const mode = (process.env.RETIRE_MODE || process.argv[2] || "plan") as RetirementMode; + if (!["plan", "dry-run", "execute", "verify"].includes(mode)) throw new Error(`invalid mode ${mode}`); + const manifestPath = path.resolve(process.env.RETIRE_MANIFEST || process.argv[3] || "legacy-l1-staking-retirement.json"); + return { mode, manifestPath }; +} + +async function main(): Promise { + const { mode, manifestPath } = parseArgs(); + if (!process.env.L1_RPC_URL) throw new Error("L1_RPC_URL is required"); + if (!fs.existsSync(manifestPath)) throw new Error(`retirement manifest not found: ${manifestPath}`); + const provider = new ethers.providers.JsonRpcProvider(process.env.L1_RPC_URL); + const manifest: RetirementManifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + if ( + !ethers.utils.isAddress(manifest.legacy.proxy) || + manifest.legacy.proxy === ZERO_ADDRESS || + !ethers.utils.isAddress(manifest.legacy.burnAdmin) || + manifest.legacy.burnAdmin === ZERO_ADDRESS || + !ethers.utils.isAddress(manifest.retirement.treasury) + ) { + throw new Error("retirement manifest contains invalid addresses"); + } + const abi = loadFrozenAbi(); + await verifyRelayEvidence(provider, manifest.relays); + await refreshManifest(provider, manifest, abi); + + console.log(JSON.stringify({ mode, snapshot: manifest.snapshot, operations: manifest.operations }, null, 2)); + if (mode === "dry-run") await dryRunOperations(provider, manifest); + if (mode === "execute") await executeOperations(provider, manifest, manifestPath, abi); + if (mode === "verify") { + const blockers = retirementBlockers(manifest); + if (blockers.length > 0) throw new Error(`retirement verification blocked:\n${blockers.join("\n")}`); + manifest.verifiedAt = new Date().toISOString(); + } + fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); +} + +if (require.main === module) { + main().catch((error) => { + console.error(error); + process.exitCode = 1; + }); +} diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index 353d9ced9..3624dcb1b 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -23,22 +23,16 @@ const config = { proofRewardPercent: 70, // challenge config // TODO to be removed later - rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', + batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], rollupChallenger: '0x48445d5DDb25a4f23C6d85D87f15B39Fe94e6867', // genesis config rollupGenesisStateRoot: '', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index d589f50a6..31db491e5 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -24,22 +24,16 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', + batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], rollupChallenger: '0x2910DB00C9537B90337b40D9732f4c356cbb84D0', // genesis config batchHeader: '00000000000000000000000000000000000000000000000000aa0feb482ae04f2a6b6b422932b5a2d537cd657ceb83008e87fce6ed6d290031010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000000a31941eb1853862c0c38f378eb0c519e9e66f0942e39b47dca38c0437ab6b3e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index 285ca9c59..12525b6af 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -26,21 +26,15 @@ const config = { rollupDelayPeriod: 86400, // challenge config - rollupProposer: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', + batchSubmitterAddresses: ['0x70997970C51812dc3A010C7d01b50e0d17dc79C8'], rollupChallenger: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65', // genesis config batchHeader: '0x00000000000000000000000000000000000000000000000000886e14341b355178d11a2c9f985f60a1a195973078b688a11aeaebb0c95db595010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000002d20dde82426d971e398b3cba11ebb60d0d740b799f85e2f95fd12a1faad8e2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x783698dCDEBdc96785c5c60ED96113612bA09c2b", diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index b0740d0b9..abbc0b834 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -21,21 +21,15 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - rollupProposer: '0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d', + batchSubmitterAddresses: ['0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d'], rollupChallenger: '0x71616250f7CAaa8a5DC295dc5851D6b1E49188a7', // genesis config batchHeader: '', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 50, + // submitter initialize config + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 50, // register sequencers l2SequencerAddresses: [ "0x25d36d94b64165f72a817ae0ff9bad2ce6914c70", diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 3657c5811..849ff3fe2 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -22,16 +22,16 @@ const config = { rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, - rollupProposer: '0x77774B33aFa9Ecef8835D25ff749ff84950e83af', + batchSubmitterAddresses: ['0x77774B33aFa9Ecef8835D25ff749ff84950e83af'], rollupChallenger: '0x77776ab9Ed7479Ff446f1E3135145e245f2B71B1', rollupGenesisStateRoot: '', withdrawRoot: '', batchHeader: '', finalizationPeriodSeconds: 600, - stakingSequencerSize: 7, - stakingLockNumber: 3, - stakingMinDeposit: 0.1, + submitterMinimumStake: 0.1, + submitterChallengeDeposit: 0.1, + submitterRewardPercentage: 100, baseFeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', l1FeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index 8e0c9786f..af76da02b 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -18,14 +18,14 @@ const config = { rollupProofWindow: 100, rollupGenesisBlockNumber: 0, proofRewardPercent: 70, - rollupProposer: '0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3', + batchSubmitterAddresses: ['0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3'], rollupChallenger: '0xF730477971E88b3162ed7FD950Be63474975bdC3', rollupGenesisStateRoot: '', finalizationPeriodSeconds: 2, - stakingMinDeposit: 1, - stakingSequencerSize: 3, - stakingLockNumber: 3, + submitterMinimumStake: 1, + submitterChallengeDeposit: 1, + submitterRewardPercentage: 100, /** * Only used for SystemConfig * --------from-------- diff --git a/contracts/src/deploy-utils.ts b/contracts/src/deploy-utils.ts index ddb59efe5..8a1a2d8b3 100644 --- a/contracts/src/deploy-utils.ts +++ b/contracts/src/deploy-utils.ts @@ -114,12 +114,14 @@ export const storage = async ( contractsName: string, contractAddress: string, deployedBlockNumber: number, + metadata: Record = {}, ): Promise => { let Contract = { name: contractsName, address: contractAddress, time: new Date().toISOString(), - number: deployedBlockNumber + number: deployedBlockNumber, + ...metadata, } if (fs.existsSync(path)) { let data = fs.readFileSync(path) @@ -170,4 +172,3 @@ export const sleep = async (ms: number): Promise => { }, ms); }); }; - diff --git a/contracts/src/types.ts b/contracts/src/types.ts index 7e518addd..74574ddf2 100644 --- a/contracts/src/types.ts +++ b/contracts/src/types.ts @@ -16,8 +16,8 @@ const ContractFactoryName = { Rollup: 'Rollup', ZkEvmVerifierV1: 'ZkEvmVerifierV1', MultipleVersionRollupVerifier: 'MultipleVersionRollupVerifier', - // staking - L1Staking: 'L1Staking', + // batch submitter + Submitter: 'Submitter', // L1 sequencer L1Sequencer: 'L1Sequencer', // gateway @@ -40,8 +40,8 @@ const ProxyStorageName = { L1MessageQueueWithGasPriceOracleProxyStorageName: 'Proxy__L1MessageQueueWithGasPriceOracle', // rollup RollupProxyStorageName: 'Proxy__Rollup', - // staking - L1StakingProxyStorageName: 'Proxy__L1Staking', + // batch submitter + SubmitterProxyStorageName: 'Proxy__Submitter', // L1 sequencer L1SequencerProxyStorageName: 'Proxy__L1Sequencer', // gateway @@ -73,8 +73,9 @@ const ImplStorageName = { RollupStorageName: 'Impl__Rollup', ZkEvmVerifierV1StorageName: 'Impl__ZkEvmVerifierV1', MultipleVersionRollupVerifierStorageName: 'Impl__MultipleVersionRollupVerifier', - // staking - L1StakingStorageName: 'Impl__L1Staking', + // batch submitter + SubmitterStorageName: 'Impl__Submitter', + SubmitterInstallStorageName: 'Install__Submitter', // L1 sequencer L1SequencerStorageName: 'Impl__L1Sequencer', // gateway @@ -95,4 +96,4 @@ export { ImplStorageName, ProxyStorageName, ContractFactoryName -} \ No newline at end of file +} diff --git a/contracts/tasks/deploy.ts b/contracts/tasks/deploy.ts index a7ea6bb6a..527f9d837 100644 --- a/contracts/tasks/deploy.ts +++ b/contracts/tasks/deploy.ts @@ -13,14 +13,14 @@ import { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, + SubmitterInstall, MessengerInit, RollupInit, GatewayInit, - StakingInit, AdminTransfer, AdminTransferConcurrently, ContractInit, - StakingRegister, + SubmitterRegister, SequencerInit, } from '../deploy/index' import { ethers } from "ethers"; @@ -97,6 +97,13 @@ task("initialize") return } + console.log('\n---------------------------------- Submitter install ----------------------------------') + err = await SubmitterInstall(hre, storagePath, deployer, config) + if (err != '') { + console.log('Submitter install failed, err: ', err) + return + } + console.log('\n---------------------------------- Messenger init ----------------------------------') err = await MessengerInit(hre, storagePath, deployer, config) if (err != '') { @@ -115,12 +122,6 @@ task("initialize") console.log('Rollup init failed, err: ', err) return } - console.log('\n---------------------------------- Staking init ----------------------------------') - err = await StakingInit(hre, storagePath, deployer, config) - if (err != '') { - console.log('Staking init failed, err: ', err) - return - } console.log('\n---------------------------------- Sequencer init ----------------------------------') err = await SequencerInit(hre, storagePath, deployer, config) if (err != '') { @@ -152,25 +153,23 @@ task("initialize") task("fund") .setAction(async (taskArgs, hre) => { - console.log('\n---------------------------------- Fund Staking ----------------------------------') + console.log('\n---------------------------------- Fund Submitters ----------------------------------') const signer = await hre.ethers.getSigners() - console.log(process.env.l2SequencerPks) - let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); - console.log(l2SequencerPkList) - for (let i = 0; i < l2SequencerPkList.length; i++) { - let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) + const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); + for (let i = 0; i < batchSubmitterPkList.length; i++) { + const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) const tx = { - to: sequencer.address, + to: submitter.address, value: ethers.utils.parseEther("100") } - let balance = (await sequencer.getBalance()).toString() + let balance = (await submitter.getBalance()).toString() if (balance.length < 20) { let receipt = await signer[0].sendTransaction(tx) await receipt.wait() } - balance = (await sequencer.getBalance()).toString() - console.log(`${sequencer.address} has balance: ${balance}`) + balance = (await submitter.getBalance()).toString() + console.log(`${submitter.address} has balance: ${balance}`) } }) @@ -181,14 +180,19 @@ task("register") // Initialization parameters const storagePath = taskArgs.storagepath const config = hre.deployConfig - let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); - for (let i = 0; i < l2SequencerPkList.length; i++) { - let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) - console.log(`\n---------------------------------- register sequencer-${i} ----------------------------------`) - console.log(`sequencer-${i}:` + await sequencer.getAddress() + ', Balance: ' + await sequencer.getBalance()) - let err = await StakingRegister(hre, storagePath, sequencer, config.l2SequencerTmKeys[i], config.l2SequencerBlsKeys[i]) + const owner = await hre.ethers.provider.getSigner(); + const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); + const configuredAddresses: string[] = config.batchSubmitterAddresses || []; + for (let i = 0; i < batchSubmitterPkList.length; i++) { + const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) + if (configuredAddresses[i] && configuredAddresses[i].toLowerCase() !== submitter.address.toLowerCase()) { + throw new Error(`batch submitter key ${i} does not match configured address`) + } + console.log(`\n---------------------------------- register submitter-${i} ----------------------------------`) + console.log(`submitter-${i}:` + submitter.address + ', Balance: ' + await submitter.getBalance()) + const err = await SubmitterRegister(hre, storagePath, owner, submitter) if (err != '') { - console.log(`Deploy Staking Sequencer-${i} failed, err: `, err) + console.log(`Register Submitter-${i} failed, err: `, err) return } } diff --git a/contracts/tasks/staking_upgrade.ts b/contracts/tasks/staking_upgrade.ts deleted file mode 100644 index 9a237e62d..000000000 --- a/contracts/tasks/staking_upgrade.ts +++ /dev/null @@ -1,901 +0,0 @@ -import "@nomiclabs/hardhat-web3" -import "@nomiclabs/hardhat-ethers" -import "@nomiclabs/hardhat-waffle" - -import fs from "fs"; -import assert from "assert" -import { task } from "hardhat/config" -import { ethers } from "ethers" -import { assertContractVariable, getContractAddressByName, awaitCondition, storage } from "../src/deploy-utils" -import { ImplStorageName, ProxyStorageName, ContractFactoryName } from "../src/types" -import { predeploys } from "../src" -import { hexlify } from "ethers/lib/utils"; - -task("rollup-deploy-init") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - const config = hre.deployConfig - const chainId = config.l2ChainID - const deployer = hre.ethers.provider.getSigner() - - const ProxyFactoryName = ContractFactoryName.DefaultProxy - const IProxyFactoryName = ContractFactoryName.DefaultProxyInterface - const RollupFactoryName = ContractFactoryName.Rollup - const RollupImplStorageName = ImplStorageName.RollupStorageName - const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) - - const RollupFactory = await hre.ethers.getContractFactory(RollupFactoryName) - const rollupNewImpl = await RollupFactory.deploy(chainId) - await rollupNewImpl.deployed() - let blockNumber = await hre.ethers.provider.getBlockNumber() - let err = await storage( - newPath, - RollupImplStorageName, - rollupNewImpl.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - console.log(`Rollup new impl deploy at ${rollupNewImpl.address}`) - - // Proxy deploy - const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) - // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin - const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") - await proxy.deployed() - blockNumber = await hre.ethers.provider.getBlockNumber() - err = await storage(newPath, RollupProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) - if (err != "") { - return err - } - console.log(`Rollup proxy deploy at ${proxy.address}`) - - // ------------------ deploy MultipleVersionRollupVerifier ----------------- - { - // deploy ZkEvmVerifierV1 - const ZkEvmVerifierV1ContractFactoryName = ContractFactoryName.ZkEvmVerifierV1 - const ZkEvmVerifierV1ImplStorageName = ImplStorageName.ZkEvmVerifierV1StorageName - const Factory = await hre.ethers.getContractFactory(ZkEvmVerifierV1ContractFactoryName) - const contract = await Factory.deploy(config.programVkey) - await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - let blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - let err = await storage(newPath, ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) - if (err != '') { - return err - } - - - // deploy MultipleVersionRollupVerifier - const ZkEvmVerifierV1Address = getContractAddressByName( - newPath, - ImplStorageName.ZkEvmVerifierV1StorageName - ) - const MultipleVersionRollupVerifierFactoryName = ContractFactoryName.MultipleVersionRollupVerifier - const MultipleVersionRollupVerifierImplStorageName = - ImplStorageName.MultipleVersionRollupVerifierStorageName - console.log("Deploy the MultipleVersionRollupVerifier ...") - const MultipleVersionRollupVerifierFactory = await hre.ethers.getContractFactory( - MultipleVersionRollupVerifierFactoryName - ) - const version = [0] - const verifiers = [ZkEvmVerifierV1Address] - const MultipleVersionRollupVerifierContract = await MultipleVersionRollupVerifierFactory.deploy( - version, - verifiers - ) - await MultipleVersionRollupVerifierContract.deployed() - await MultipleVersionRollupVerifierContract.initialize(proxy.address) - console.log( - "%s=%s ; TX_HASH: %s", - MultipleVersionRollupVerifierImplStorageName, - MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), - MultipleVersionRollupVerifierContract.deployTransaction.hash - ) - blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - err = await storage( - newPath, - MultipleVersionRollupVerifierImplStorageName, - MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // ------------------ rollup initialize ----------------- - { - const IRollupProxy = await hre.ethers.getContractAt(IProxyFactoryName, proxy.address, deployer) - console.log("Upgrading the Rollup proxy...") - const finalizationPeriodSeconds: number = config.finalizationPeriodSeconds - const proofWindow: number = config.rollupProofWindow - - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1StakingProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1StakingProxyStorageName - ) - const MultipleVersionRollupVerifierContractAddress = getContractAddressByName( - newPath, - ImplStorageName.MultipleVersionRollupVerifierStorageName - ) - if ( - !ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || - !ethers.utils.isAddress(MultipleVersionRollupVerifierContractAddress) || - !ethers.utils.isAddress(L1StakingProxyAddress) - ) { - console.error("please check your address") - return "" - } - - // Upgrade and initialize the proxy. - await IRollupProxy.upgradeToAndCall( - rollupNewImpl.address, - RollupFactory.interface.encodeFunctionData("initialize", [ - L1StakingProxyAddress, - L1MessageQueueWithGasPriceOracleProxyAddress, - MultipleVersionRollupVerifierContractAddress, - finalizationPeriodSeconds, - proofWindow, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IRollupProxy.implementation()).toLocaleLowerCase() === - rollupNewImpl.address.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - // params check - const contractTmp = new ethers.Contract(proxy.address, RollupFactory.interface, deployer) - await assertContractVariable(contractTmp, "l1StakingContract", L1StakingProxyAddress) - await assertContractVariable(contractTmp, "messageQueue", L1MessageQueueWithGasPriceOracleProxyAddress) - await assertContractVariable(contractTmp, "verifier", MultipleVersionRollupVerifierContractAddress) - await assertContractVariable(contractTmp, "finalizationPeriodSeconds", finalizationPeriodSeconds) - await assertContractVariable(contractTmp, "proofWindow", proofWindow) - await assertContractVariable(contractTmp, "owner", await deployer.getAddress()) - - // Wait for the transaction to execute properly. - console.log(`RollupProxy upgrade success, Rollup address at ${proxy.address}`) - } - - // ------------------ Admin transfer ----------------- - { - const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() - const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - proxy.address, - deployer - ) - { - const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() - const admin = (await IProxyContract.admin()).toLocaleLowerCase() - if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { - return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` - } - if (admin !== deployerAddr) { - return `Proxy admin address ${admin} should deployer address ${deployerAddr}` - } - } - console.log(`change rollup admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) - const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) - await res.wait() - await assertContractVariable( - IProxyContract, - "admin", - ProxyAdminImplAddr, - ProxyAdminImplAddr // caller - ) - console.log(`admin transfer successful`) - } - }) - -task("rollup-import-genesis-batch") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const newPath = taskArgs.newpath - const config = hre.deployConfig - const deployer = hre.ethers.provider.getSigner() - // ------------------ rollup import genesis batch ----------------- - { - const NewRollupContractAddr = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const Rollup = await hre.ethers.getContractAt(ContractFactoryName.Rollup, NewRollupContractAddr, deployer) - // import genesis batch - const batchHeader: string = config.batchHeader - - // submitter and challenger - const submitter: string = config.rollupProposer - const challenger: string = config.rollupChallenger - if (!ethers.utils.isAddress(submitter) || !ethers.utils.isAddress(challenger)) { - console.error("please check your address") - return "" - } - let res = await Rollup.importGenesisBatch(batchHeader) - let rec = await res.wait() - console.log( - `importGenesisBatch(%s) ${rec.status == 1 ? "success" : "failed"}`, - batchHeader, - ) - res = await Rollup.addChallenger(challenger) - rec = await res.wait() - console.log(`addChallenger(%s) ${rec.status == 1 ? "success" : "failed"}`, challenger) - const batch = await Rollup.batchBaseStore(0) - assert(batch.batchHash.toLowerCase() != "", `[FATAL] import genesis batch failed`) - } - }) - -task("l1mq-upgrade") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - const EnforcedTxGatewayAddress = getContractAddressByName( - storagePath, - ProxyStorageName.EnforcedTxGatewayProxyStorageName - ) - const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - - // deploy L1MessageQueueWithGasPriceOracle impl - { - const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const Factory = await hre.ethers.getContractFactory(L1MessageQueueWithGasPriceOracleFactoryName) - const contract = await Factory.deploy( - L1CrossDomainMessengerProxyAddress, - NewRollupProxyAddress, - EnforcedTxGatewayAddress - ) - await contract.deployed() - console.log( - "%s=%s ; TX_HASH: %s", - ImplStorageName.L1MessageQueueWithGasPriceOracle, - contract.address.toLocaleLowerCase(), - contract.deployTransaction.hash - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage( - newPath, - ImplStorageName.L1MessageQueueWithGasPriceOracle, - contract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // L1MessageQueueWithGasPriceOracle proxy upgrade - { - const L1MessageQueueWithGasPriceOracleNewImplAddress = getContractAddressByName( - newPath, - ImplStorageName.L1MessageQueueWithGasPriceOracle - ) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) - const res = await proxyAdmin.upgrade( - L1MessageQueueWithGasPriceOracleProxyAddress, - L1MessageQueueWithGasPriceOracleNewImplAddress - ) - const rec = await res.wait() - console.log(`upgrade l1MessageQueueWithGasPriceOracle.rollup ${rec.status === 1}`) - } - }) - -task("l1cdm-upgrade") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - - // deploy l1CrossDomainMessenger impl - { - const Factory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) - const contract = await Factory.deploy() - await contract.deployed() - console.log( - "%s=%s ; TX_HASH: %s", - L1CrossDomainMessengerImplStorageName, - contract.address.toLocaleLowerCase(), - contract.deployTransaction.hash - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage( - newPath, - L1CrossDomainMessengerImplStorageName, - contract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // l1CrossDomainMessenger proxy upgrade - { - const L1CrossDomainMessengerNewImplAddress = getContractAddressByName( - newPath, - L1CrossDomainMessengerImplStorageName - ) - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) - const res = await proxyAdmin.upgrade( - L1CrossDomainMessengerProxyAddress, - L1CrossDomainMessengerNewImplAddress - ) - const rec = await res.wait() - console.log(`upgrade l1CrossDomainMessenger ${rec.status === 1}`) - } - - // l1CrossDomainMessenger update Rollup address - { - const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const L1CDMFactory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) - const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) - const res = await l1CrossDomainMessenger.updateRollup(NewRollupProxyAddress) - const rec = await res.wait() - console.log(`update l1CrossDomainMessenger.rollup ${rec.status === 1}`) - } - }) - - -task("l1staking-deploy-init") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - const config = hre.deployConfig - const deployer = hre.ethers.provider.getSigner() - - const ProxyFactoryName = ContractFactoryName.DefaultProxy - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName - const WhitelistImplAddress = getContractAddressByName(storagePath, ImplStorageName.Whitelist) - const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName(storagePath, ProxyStorageName.L1CrossDomainMessengerProxyStorageName) - - // deploy L1Staking proxy - { - const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) - // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin - const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") - await proxy.deployed() - const blockNumber = await hre.ethers.provider.getBlockNumber() - const err = await storage(newPath, L1StakingProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) - if (err != "") { - console.log(`deploy L1Staking proxy failed ${err}`) - return err - } - console.log(`L1Staking proxy deploy at ${proxy.address}`) - } - - // deploy impl - { - const Factory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - const contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) - await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage(newPath, ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) - if (err != '') { - console.log(`deploy L1Staking implemention failed ${err}`) - return err - } - } - - // upgrade - { - const RollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - // Staking config - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingImplAddress = getContractAddressByName(newPath, ImplStorageName.L1StakingStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) - - console.log('Upgrading the Staking proxy...') - const admin: string = config.contractAdmin - const stakingChallengerRewardPercentage: number = config.stakingChallengerRewardPercentage - const limit: number = config.stakingMinDeposit - const lock: number = config.stakingLockNumber - const gasLimitAdd: number = config.stakingCrossChainGaslimitAdd - const gasLimitRemove: number = config.stakingCrossChainGaslimitRemove - - if (!ethers.utils.isAddress(admin) - || lock <= 0 - || limit <= 0 - || gasLimitAdd <= 0 - || gasLimitRemove <= 0 - || stakingChallengerRewardPercentage > 100 - || stakingChallengerRewardPercentage <= 0 - ) { - console.error('please check your address') - return '' - } - - // Upgrade and initialize the proxy. - await IL1StakingProxy.upgradeToAndCall( - L1StakingImplAddress, - L1StakingFactory.interface.encodeFunctionData('initialize', [ - RollupProxyAddress, - hre.ethers.utils.parseEther(limit.toString()), - hre.ethers.utils.parseEther(lock.toString()), - stakingChallengerRewardPercentage, - gasLimitAdd, - gasLimitRemove, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - - const contractTmp = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - deployer, - ) - - await assertContractVariable( - contractTmp, - 'rollupContract', - RollupProxyAddress - ) - await assertContractVariable( - contractTmp, - 'rewardPercentage', - stakingChallengerRewardPercentage - ) - await assertContractVariable( - contractTmp, - 'stakingValue', - hre.ethers.utils.parseEther(limit.toString()) - ) - await assertContractVariable( - contractTmp, - 'withdrawalLockBlocks', - hre.ethers.utils.parseEther(lock.toString()) - ) - await assertContractVariable( - contractTmp, - 'gasLimitAddStaker', - gasLimitAdd - ) - await assertContractVariable( - contractTmp, - 'gasLimitRemoveStakers', - gasLimitRemove - ) - await assertContractVariable( - contractTmp, - 'owner', - await deployer.getAddress(), - ) - // Wait for the transaction to execute properly. - console.log('StakingProxy upgrade success') - } - - // ------------------ Admin transfer ----------------- - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() - const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - L1StakingProxyAddress, - deployer - ) - { - const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() - const admin = (await IProxyContract.admin()).toLocaleLowerCase() - if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { - return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` - } - if (admin !== deployerAddr) { - return `Proxy admin address ${admin} should deployer address ${deployerAddr}` - } - } - console.log(`change L1Staking admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) - const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) - await res.wait() - await assertContractVariable( - IProxyContract, - "admin", - ProxyAdminImplAddr, - ProxyAdminImplAddr // caller - ) - console.log(`admin transfer successful`) - } - - // set L1Staking address to gasPriceOracle whitelist - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) - let addList = [L1StakingProxyAddress] - const res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) - await res.wait() - for (let i = 0; i < addList.length; i++) { - let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) - if (res != true) { - console.error('whitelist check failed') - return '' - } - } - console.log(`add ${addList} to whitelist success`) - } - - // set staker whitelist - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) - const whiteListAdd = config.l2SequencerAddresses - // set sequencer to white list - await L1Staking.updateWhitelist(whiteListAdd, []) - for (let i = 0; i < config.l2SequencerAddresses.length; i++) { - // Wait for the transaction to execute properly. - await awaitCondition( - async () => { - return ( - await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true - ) - }, - 3000, - 1000 - ) - console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) - } - } - }) - -task("check-params") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - const RollupNewProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const L1CDMFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1CrossDomainMessenger) - const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) - let res = await l1CrossDomainMessenger.rollup() - assert( - RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), - `l1CrossDomainMessenger assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` - ) - - const L1MQFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1MessageQueueWithGasPriceOracle) - const l1mq = L1MQFactory.attach(L1MessageQueueWithGasPriceOracleProxyAddress) - res = await l1mq.ROLLUP_CONTRACT() - assert( - RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), - `l1mq assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` - ) - console.log("Check new rollup address success") - }) - -// test command -// rm -rf ./deployFile.json && \ -// yarn hardhat deploy --storagepath ./deployFile.json --network l1 && \ -// yarn hardhat initialize --storagepath ./deployFile.json --network l1 && \ -// yarn hardhat fund --network l1 && \ -// yarn hardhat register --storagepath ./deployFile.json --network l1 && \ -// rm -rf ./newFile.json && \ -// yarn hardhat rollup-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1mq-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1cdm-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat check-params --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1staking-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat register --storagepath ./newFile.json --network l1 - -// immutable upgrade test -task("impl-test") - .setAction(async (taskArgs, hre) => { - const deployer = hre.ethers.provider.getSigner() - const V1Factory = await hre.ethers.getContractFactory("TestUpgradeV1") - const V2Factory = await hre.ethers.getContractFactory("TestUpgradeV2") - - const v1Impl = await V1Factory.deploy() - await v1Impl.deployed() - const v2Impl = await V2Factory.deploy() - await v2Impl.deployed() - console.log(`V1 and V2 impl deploy success and v1: ${v1Impl.address} , v2: ${v2Impl.address}`) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = await ProxyAdminFactory.deploy() - await proxyAdmin.deployed() - const ProxyFactory = await hre.ethers.getContractFactory(ContractFactoryName.DefaultProxy) - const proxy = await ProxyFactory.deploy(v1Impl.address, await deployer.getAddress(), "0x") - await proxy.deployed() - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - proxy.address, - deployer - ) - - // transfer owner to proxy admin - { - const res = await IProxyContract.changeAdmin(proxyAdmin.address) - const rec = await res.wait() - console.log(`proxy admin change to proxy admin ${rec.status === 1}`) - } - - const consoleParams = async (factory) => { - const contractTmp = new ethers.Contract( - proxy.address, - factory.interface, - hre.ethers.provider, - ) - let va = await contractTmp.va({ from: hre.ethers.constants.AddressZero }) - let vb = await contractTmp.vb({ from: hre.ethers.constants.AddressZero }) - let vc = await contractTmp.vc({ from: hre.ethers.constants.AddressZero }) - let version = await contractTmp.version({ from: hre.ethers.constants.AddressZero }) - console.log(`va ${va} ; vb ${vb} ; vc ${vc} ; version ${version}`) - } - let contract = new ethers.Contract( - proxy.address, - V1Factory.interface, - deployer, - ) - let res = await contract.setVersion(100) - let rec = await res.wait() - console.log(`update version to 100 ${rec.status === 1}`) - await consoleParams(V1Factory) - - // upgrade - { - const res = await proxyAdmin.upgrade(proxy.address, v2Impl.address) - const rec = await res.wait() - console.log(`upgrade to v2 impl ${rec.status === 1}`) - } - contract = new ethers.Contract( - proxy.address, - V2Factory.interface, - deployer, - ) - res = await contract.setVersion(101) - rec = await res.wait() - console.log(`update version to 101 ${rec.status === 1}`) - res = await contract.setOtherVersion(99) - rec = await res.wait() - console.log(`update otherVersion to 99 ${rec.status === 1}`) - console.log("upgrade success") - await consoleParams(V2Factory) - }) - -// ------------------------------------ L2 Upgrade ------------------------------------ -task("gov-upgrade") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const GovFactory = await hre.ethers.getContractFactory("Gov") - const newGovImpl = await GovFactory.deploy() - await newGovImpl.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Gov, - newGovImpl.address, - GovFactory.interface.encodeFunctionData('initializeV2', [ - l2Config.govVotingDuration, - l2Config.govBatchBlockInterval, - l2Config.govBatchMaxBytes, - l2Config.govBatchTimeout, - l2Config.govBatchMaxChunks, - l2Config.govRollupEpoch, - ]) - ) - const rec = await res.wait() - console.log(`gov upgrade ${rec.status === 1}`) - }) - -task("distribute-deploy") - .setAction(async (taskArgs, hre) => { - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const DistributeFactory = await hre.ethers.getContractFactory("Distribute") - const distribute = await DistributeFactory.deploy() - await distribute.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Distribute, - distribute.address, - DistributeFactory.interface.encodeFunctionData('initialize', []) - ) - const rec = await res.wait() - console.log(`distribute upgrade ${rec.status === 1}, new impl ${distribute.address}`) - }) - -task("morph-token-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const MorphTokenFactory = await hre.ethers.getContractFactory("MorphToken") - const morphToken = await MorphTokenFactory.deploy() - await morphToken.deployed() - - const res = await proxyAdmin.upgradeAndCall( - predeploys.MorphToken, - morphToken.address, - MorphTokenFactory.interface.encodeFunctionData('initialize', [ - l2Config.morphTokenName, - l2Config.morphTokenSymbol, - l2Config.morphTokenOwner, - hre.ethers.utils.parseEther(l2Config.morphTokenInitialSupply.toString()), - l2Config.morphTokenDailyInflationRate, - ]) - ) - const rec = await res.wait() - console.log(`morphToken upgrade ${rec.status === 1}, new impl ${morphToken.address}`) - }) - -task("sequencer-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const SequencerFactory = await hre.ethers.getContractFactory("Sequencer") - const sequencer = await SequencerFactory.deploy() - await sequencer.deployed() - - // l2Config - let addresses = [] - for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { - addresses.push(l2Config.l2StakingAddresses[i]) - } - const res = await proxyAdmin.upgradeAndCall( - predeploys.Sequencer, - sequencer.address, - SequencerFactory.interface.encodeFunctionData( - 'initialize', - [addresses]) - ) - const rec = await res.wait() - console.log(`sequencer upgrade ${rec.status === 1}, new impl ${sequencer.address}`) - }) - -task("record-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const RecordFactory = await hre.ethers.getContractFactory("Record") - const record = await RecordFactory.deploy() - await record.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Record, - record.address, - RecordFactory.interface.encodeFunctionData('initialize', [ - l2Config.recordOracleAddress, - l2Config.recordNextBatchSubmissionIndex, - ]) - ) - const rec = await res.wait() - console.log(`Record upgrade ${rec.status === 1}, new impl ${record.address}`) - }) - -task("l2-staking-deploy") - .addParam("newpath") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const newPath = taskArgs.newpath - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const L1StakingProxyAddr = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const L2StakingFactory = await hre.ethers.getContractFactory("L2Staking") - const staking = await L2StakingFactory.deploy(L1StakingProxyAddr) - await staking.deployed() - - let infos = [] - for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { - let info = { - addr: l2Config.l2StakingAddresses[i], - tmKey: l2Config.l2StakingTmKeys[i], - blsKey: l2Config.l2StakingBlsKeys[i], - } - infos.push(info) - } - const res = await proxyAdmin.upgradeAndCall( - predeploys.L2Staking, - staking.address, - L2StakingFactory.interface.encodeFunctionData('initialize', [ - l2Config.l2StakingSequencerMaxSize, - l2Config.l2StakingUnDelegatedLockEpochs, - l2Config.l2StakingRewardStartTime, - infos, - ]) - ) - const rec = await res.wait() - console.log(`L2Staking upgrade ${rec.status === 1}, new impl ${staking.address}`) - }) \ No newline at end of file From d91248953a742e08475acda64b617d5c26a18610 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:31:47 +0800 Subject: [PATCH 04/38] feat(node): use static validators after upgrade --- node/cmd/node/main.go | 60 +++++++++--- node/core/centralization_cleanup_test.go | 113 +++++++++++++++++++++++ node/core/config.go | 60 +++++++++++- node/core/executor.go | 92 +++++++++++------- node/core/sequencers.go | 36 +++++--- node/derivation/config.go | 5 - node/derivation/config_test.go | 26 ------ node/flags/flags.go | 17 +--- 8 files changed, 305 insertions(+), 104 deletions(-) create mode 100644 node/core/centralization_cleanup_test.go diff --git a/node/cmd/node/main.go b/node/cmd/node/main.go index 08c1c5c4d..e9148ffaf 100644 --- a/node/cmd/node/main.go +++ b/node/cmd/node/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/binary" "fmt" "net" "net/http" @@ -17,6 +18,7 @@ import ( "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" "github.com/prometheus/client_golang/prometheus/promhttp" + tmconfig "github.com/tendermint/tendermint/config" tmcrypto "github.com/tendermint/tendermint/crypto" tmlog "github.com/tendermint/tendermint/libs/log" tmnode "github.com/tendermint/tendermint/node" @@ -136,6 +138,9 @@ func L2NodeMain(ctx *cli.Context) error { if err != nil { return err } + if err := restorePersistedUpgradeHeight(tmCfg); err != nil { + return fmt.Errorf("restore persisted sequencer upgrade height: %w", err) + } // Load derivation config here (not just before the switch below): its // VerifyMode decides whether this node runs the Tendermint consensus node, @@ -161,25 +166,14 @@ func L2NodeMain(ctx *cli.Context) error { pubKey, _ = tmVal.GetPubKey() } - // Reuse the shared syncer instance -- DevSequencer mode is the only path - // that pulls a syncer out of NewExecutor, so we hand back the same one - // rather than letting NewExecutor open a second store + syncer. + // Reuse the shared syncer instance. NewExecutor starts it independently of + // validator membership, and Derivation.Start may safely invoke Start again. newSyncerFunc := func() (*sync.Syncer, error) { return syncer, nil } executor, err = node.NewExecutor(newSyncerFunc, nodeConfig, pubKey) if err != nil { return err } - // Eagerly start the L1 message syncer for post-upgrade sequencer nodes that - // are NOT in the PBFT validator set (separated-deployment / HA cluster). - // In the combined-deployment case, updateSequencerSet already started the - // syncer inside NewExecutor, so SetSyncer is a no-op there. - if signer != nil && executor.Syncer() == nil { - executor.SetSyncer(syncer) - syncer.Start() - nodeConfig.Logger.Info("L1 syncer start", "reason", "post-upgrade always start") - } - haService, err = initHAService(ctx, home, nodeConfig.Logger) if err != nil { return err @@ -296,6 +290,46 @@ func L2NodeMain(ctx *cli.Context) error { return nil } +// upgradeHeightSnapshotStore holds the height restored from Tendermint's state +// DB while NewExecutor is constructed. SetupNode subsequently rewires the +// upgrade package to the live DB. An unexpected early write fails hard instead +// of pretending that critical consensus state was persisted. +type upgradeHeightSnapshotStore struct { + height int64 +} + +func (s upgradeHeightSnapshotStore) Get([]byte) ([]byte, error) { + if s.height < 0 { + return nil, nil + } + var encoded [8]byte + binary.BigEndian.PutUint64(encoded[:], uint64(s.height)) + return encoded[:], nil +} + +func (upgradeHeightSnapshotStore) Set([]byte, []byte) error { + return fmt.Errorf("live Tendermint upgrade store is not wired yet") +} + +// restorePersistedUpgradeHeight makes the persisted H available before +// NewExecutor performs its initial validator lookup. Tendermint normally wires +// this store inside NewNode, which is necessarily constructed after Executor. +func restorePersistedUpgradeHeight(tmCfg *tmconfig.Config) error { + stateDB, err := tmnode.DefaultDBProvider(&tmnode.DBContext{ID: "state", Config: tmCfg}) + if err != nil { + return err + } + if err := upgrade.SetStore(stateDB); err != nil { + _ = stateDB.Close() + return err + } + height := upgrade.UpgradeBlockHeight() + if err := stateDB.Close(); err != nil { + return err + } + return upgrade.SetStore(upgradeHeightSnapshotStore{height: height}) +} + // initHAService builds the HA config and creates the HAService. // Loading order: defaults → config file → flag overrides → auto-resolve → validate. // Returns nil (no error) if HA is not enabled. diff --git a/node/core/centralization_cleanup_test.go b/node/core/centralization_cleanup_test.go new file mode 100644 index 000000000..c7f0ea859 --- /dev/null +++ b/node/core/centralization_cleanup_test.go @@ -0,0 +1,113 @@ +package node + +import ( + "bytes" + "errors" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/upgrade" + + nodesync "morph-l2/node/sync" +) + +func TestParseStaticValidatorTmKeys(t *testing.T) { + keyA := strings.Repeat("11", tmKeySize) + keyB := strings.Repeat("22", tmKeySize) + + keysAB, hashAB, err := parseStaticValidatorTmKeys([]string{keyB, "0x" + keyA}) + require.NoError(t, err) + require.Len(t, keysAB, 2) + require.True(t, bytes.Compare(keysAB[0], keysAB[1]) < 0, "keys must be canonicalized lexicographically") + + keysBA, hashBA, err := parseStaticValidatorTmKeys([]string{keyA + "," + keyB}) + require.NoError(t, err) + require.Equal(t, keysAB, keysBA) + require.Equal(t, hashAB, hashBA, "input order must not change the network key-set hash") + + for _, tc := range []struct { + name string + values []string + }{ + {name: "empty"}, + {name: "short", values: []string{"01"}}, + {name: "invalid hex", values: []string{strings.Repeat("zz", tmKeySize)}}, + {name: "duplicate", values: []string{keyA, "0x" + keyA}}, + } { + t.Run(tc.name, func(t *testing.T) { + _, _, err := parseStaticValidatorTmKeys(tc.values) + require.Error(t, err) + }) + } +} + +func TestValidatorSetAtHeightUpgradeBoundary(t *testing.T) { + originalHeight := upgrade.UpgradeBlockHeight() + upgrade.SetUpgradeBlockHeight(100) + t.Cleanup(func() { upgrade.SetUpgradeBlockHeight(originalHeight) }) + + legacyKeys := [][]byte{bytes.Repeat([]byte{0x11}, tmKeySize)} + staticKeys := [][]byte{bytes.Repeat([]byte{0x22}, tmKeySize)} + legacyCalls := 0 + executor := &Executor{ + staticValidatorTmKeys: staticKeys, + legacyValidatorSetAtHeightFunc: func(int64) ([][]byte, error) { + legacyCalls++ + return cloneValidatorKeys(legacyKeys), nil + }, + } + + for _, height := range []uint64{99, 100} { + got, err := executor.validatorSetAtHeight(height) + require.NoError(t, err) + require.Equal(t, legacyKeys, got) + } + got, err := executor.validatorSetAtHeight(101) + require.NoError(t, err) + require.Equal(t, staticKeys, got) + require.Equal(t, 2, legacyCalls, "H+1 must not call either historical contract") + + got[0][0] ^= 0xff + require.Equal(t, byte(0x22), executor.staticValidatorTmKeys[0][0], "callers must not mutate the configured set") +} + +func TestEnsureSyncerStartedIndependentOfValidatorMembership(t *testing.T) { + created := 0 + fakeSyncer := nodesync.NewFakeSyncer(nil) + executor := &Executor{ + newSyncerFunc: func() (*nodesync.Syncer, error) { + created++ + return fakeSyncer, nil + }, + } + + require.NoError(t, executor.ensureSyncerStarted()) + require.NoError(t, executor.ensureSyncerStarted()) + require.Equal(t, 1, created) + require.Same(t, fakeSyncer, executor.l1MsgReader) +} + +func TestEnsureSyncerStartedKeepsFactoryError(t *testing.T) { + created := 0 + wantErr := errors.New("factory failed") + executor := &Executor{ + newSyncerFunc: func() (*nodesync.Syncer, error) { + created++ + return nil, wantErr + }, + } + + require.ErrorIs(t, executor.ensureSyncerStarted(), wantErr) + require.ErrorIs(t, executor.ensureSyncerStarted(), wantErr) + require.Equal(t, 1, created) + require.Nil(t, executor.l1MsgReader) +} + +func TestAllValidatorEntryPointsUseUnifiedResolver(t *testing.T) { + source, err := os.ReadFile("executor.go") + require.NoError(t, err) + require.Equal(t, 3, strings.Count(string(source), ".validatorSetAtHeight("), + "NewExecutor and both DeliverBlock branches must use the H/H+1 resolver") +} diff --git a/node/core/config.go b/node/core/config.go index c3276cdec..72e91d37d 100644 --- a/node/core/config.go +++ b/node/core/config.go @@ -1,16 +1,20 @@ package node import ( + "bytes" "crypto/rand" + "encoding/hex" "errors" "fmt" "io" "os" "path/filepath" + "slices" "strings" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/common/hexutil" + gethcrypto "github.com/morph-l2/go-ethereum/crypto" tmconfig "github.com/tendermint/tendermint/config" tmflags "github.com/tendermint/tendermint/libs/cli/flags" tmlog "github.com/tendermint/tendermint/libs/log" @@ -33,7 +37,9 @@ type Config struct { L2StakingAddress common.Address `json:"l2staking_address"` MaxL1MessageNumPerBlock uint64 `json:"max_l1_message_num_per_block"` BlsKeyCheckForkHeight uint64 `json:"bls_key_check_fork_height"` - DevSequencer bool `json:"dev_sequencer"` + StaticValidatorTmKeys [][]byte `json:"static_validator_tm_keys"` + StaticValidatorKeySetHash common.Hash `json:"static_validator_key_set_hash"` + StaticValidatorKeySource string `json:"static_validator_key_source"` Logger tmlog.Logger `json:"logger"` } @@ -142,9 +148,13 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { } } - if ctx.GlobalIsSet(flags.DevSequencer.Name) { - c.DevSequencer = ctx.GlobalBool(flags.DevSequencer.Name) + keys, keySetHash, err := parseStaticValidatorTmKeys(ctx.GlobalStringSlice(flags.StaticValidatorTmKeys.Name)) + if err != nil { + return fmt.Errorf("invalid --%s: %w", flags.StaticValidatorTmKeys.Name, err) } + c.StaticValidatorTmKeys = keys + c.StaticValidatorKeySetHash = keySetHash + c.StaticValidatorKeySource = "cli/env" if ctx.GlobalIsSet(flags.MainnetFlag.Name) { c.BlsKeyCheckForkHeight = MainnetBlsKeyCheckForkHeight @@ -153,3 +163,47 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { return nil } + +// parseStaticValidatorTmKeys validates and canonicalizes the network-wide +// Tendermint ed25519 validator key set. Keys are fixed-width, so hashing the +// sorted concatenation is unambiguous and gives operators a compact value to +// compare across every node before the upgrade boundary is activated. +func parseStaticValidatorTmKeys(values []string) ([][]byte, common.Hash, error) { + var encodedKeys []string + for _, value := range values { + for _, key := range strings.Split(value, ",") { + if key = strings.TrimSpace(key); key != "" { + encodedKeys = append(encodedKeys, key) + } + } + } + if len(encodedKeys) == 0 { + return nil, common.Hash{}, errors.New("at least one Tendermint ed25519 public key is required") + } + + keys := make([][]byte, 0, len(encodedKeys)) + seen := make(map[string]struct{}, len(encodedKeys)) + for i, encoded := range encodedKeys { + encoded = strings.TrimPrefix(encoded, "0x") + if len(encoded) != tmKeySize*2 { + return nil, common.Hash{}, fmt.Errorf("key %d must decode to exactly %d bytes", i, tmKeySize) + } + key, err := hex.DecodeString(encoded) + if err != nil { + return nil, common.Hash{}, fmt.Errorf("key %d is not valid hex: %w", i, err) + } + fingerprint := string(key) + if _, ok := seen[fingerprint]; ok { + return nil, common.Hash{}, fmt.Errorf("key %d duplicates another Tendermint ed25519 public key", i) + } + seen[fingerprint] = struct{}{} + keys = append(keys, key) + } + + slices.SortFunc(keys, bytes.Compare) + canonical := make([]byte, 0, len(keys)*tmKeySize) + for _, key := range keys { + canonical = append(canonical, key...) + } + return keys, gethcrypto.Keccak256Hash(canonical), nil +} diff --git a/node/core/executor.go b/node/core/executor.go index 0c581973e..304340bb6 100644 --- a/node/core/executor.go +++ b/node/core/executor.go @@ -17,6 +17,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/l2node" tmlog "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/upgrade" "morph-l2/bindings/bindings" "morph-l2/node/sync" @@ -35,6 +36,8 @@ type Executor struct { newSyncerFunc NewSyncerFunc syncer *sync.Syncer + syncerOnce syncos.Once + syncerErr error sequencerCaller *bindings.SequencerCaller l2StakingCaller *bindings.L2StakingCaller @@ -42,10 +45,15 @@ type Executor struct { currentSeqHash *[32]byte seqTmKeySet map[[tmKeySize]byte]struct{} - nextValidators [][]byte - tmPubKey []byte - isSequencer bool - devSequencer bool + nextValidators [][]byte + staticValidatorTmKeys [][]byte + tmPubKey []byte + isSequencer bool + + // legacyValidatorSetAtHeightFunc is a test-only seam for exercising the + // persisted H/H+1 boundary without an L2 RPC. Production leaves it nil and + // uses the protected historical getter body below. + legacyValidatorSetAtHeightFunc func(int64) ([][]byte, error) blsKeyCheckForkHeight uint64 @@ -102,28 +110,30 @@ func NewExecutor(newSyncFunc NewSyncerFunc, config *Config, tmPubKey crypto.PubK nextL1MsgIndex: index, maxL1MsgNumPerBlock: config.MaxL1MessageNumPerBlock, newSyncerFunc: newSyncFunc, - devSequencer: config.DevSequencer, + staticValidatorTmKeys: cloneValidatorKeys(config.StaticValidatorTmKeys), blsKeyCheckForkHeight: config.BlsKeyCheckForkHeight, logger: logger, metrics: PrometheusMetrics("morphnode"), } - if config.DevSequencer { - executor.syncer, err = executor.newSyncerFunc() - if err != nil { - return nil, err - } - //executor.syncer.Start() - executor.l1MsgReader = executor.syncer - return executor, nil - } - - // Get current height for initial sequencer set update + // Resolve the validator set through the same persisted H/H+1 boundary used + // by both DeliverBlock paths. At H the historical contracts still apply; + // H+1 and later never call those contracts. currentHeight, err := l2Client.BlockNumber(context.Background()) if err != nil { return nil, err } - if _, err = executor.updateSequencerSet(currentHeight); err != nil { + executor.nextValidators, err = executor.validatorSetAtHeight(currentHeight) + if err != nil { + return nil, err + } + logger.Info("static validator configuration", + "keyCount", len(config.StaticValidatorTmKeys), + "keySetHash", config.StaticValidatorKeySetHash.Hex(), + "keySetHashAlgorithm", "keccak256(sorted-concat-32-byte-keys)", + "upgradeHeight", upgrade.UpgradeBlockHeight(), + "source", config.StaticValidatorKeySource) + if err := executor.ensureSyncerStarted(); err != nil { return nil, err } @@ -264,10 +274,7 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n if wrappedBlock.Number <= height { e.logger.Info("block already delivered by geth (via P2P sync)", "block_number", wrappedBlock.Number) - if e.devSequencer { - return consensusData.ValidatorSet, nil - } - return e.getValidatorsAtHeight(int64(wrappedBlock.Number)) + return e.validatorSetAtHeight(wrappedBlock.Number) } // We only accept the continuous blocks for now. @@ -307,11 +314,9 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n e.updateNextL1MessageIndex(l2Block) - newValidatorSet := consensusData.ValidatorSet - if !e.devSequencer { - if newValidatorSet, err = e.updateSequencerSet(l2Block.Number); err != nil { - return nil, err - } + newValidatorSet, err := e.validatorSetAtHeight(l2Block.Number) + if err != nil { + return nil, err } e.metrics.Height.Set(float64(l2Block.Number)) @@ -375,17 +380,14 @@ func (e *Executor) L2Client() *types.RetryableClient { } // Syncer returns the current L1 message syncer instance, or nil if not yet -// initialized. Callers can use this to detect whether the syncer has already -// been set up (e.g. by updateSequencerSet in the PBFT-validator path) and -// avoid creating a duplicate. +// initialized. func (e *Executor) Syncer() *sync.Syncer { return e.syncer } // SetSyncer installs a pre-built syncer on the executor and wires it in as the -// l1MsgReader. This is intended for the V2/HA separated-deployment case, where -// a node holds a sequencer signer but is not a PBFT validator, so the normal -// lazy-init path in updateSequencerSet never fires. +// l1MsgReader. ensureSyncerStarted will start the installed instance instead +// of invoking the factory. // // The call is idempotent: if a syncer is already set, it is left untouched. func (e *Executor) SetSyncer(s *sync.Syncer) { @@ -396,6 +398,32 @@ func (e *Executor) SetSyncer(s *sync.Syncer) { e.l1MsgReader = s } +// ensureSyncerStarted wires and starts the L1 message reader independently of +// validator membership. Both this guard and Syncer.Start are idempotent: the +// former prevents duplicate construction, while the latter tolerates the +// derivation service invoking Start on the shared instance as well. +func (e *Executor) ensureSyncerStarted() error { + e.syncerOnce.Do(func() { + if e.syncer == nil { + if e.newSyncerFunc == nil { + e.syncerErr = errors.New("syncer factory is nil") + return + } + e.syncer, e.syncerErr = e.newSyncerFunc() + } + if e.syncerErr != nil { + return + } + if e.syncer == nil { + e.syncerErr = errors.New("syncer factory returned nil") + return + } + e.l1MsgReader = e.syncer + go e.syncer.Start() + }) + return e.syncerErr +} + // ============================================================================ // L2NodeV2 interface implementation for sequencer mode // ============================================================================ diff --git a/node/core/sequencers.go b/node/core/sequencers.go index 1323c090f..c19f9335e 100644 --- a/node/core/sequencers.go +++ b/node/core/sequencers.go @@ -7,10 +7,32 @@ import ( "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/crypto/bls12381" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/upgrade" ) const tmKeySize = ed25519.PubKeySize +func cloneValidatorKeys(keys [][]byte) [][]byte { + cloned := make([][]byte, len(keys)) + for i := range keys { + cloned[i] = bytes.Clone(keys[i]) + } + return cloned +} + +// validatorSetAtHeight is the single validator data-source boundary. The +// upgrade package intentionally switches strictly after the persisted height: +// H is historical, H+1 is static. +func (e *Executor) validatorSetAtHeight(height uint64) ([][]byte, error) { + if upgrade.IsUpgraded(int64(height)) { + return cloneValidatorKeys(e.staticValidatorTmKeys), nil + } + if e.legacyValidatorSetAtHeightFunc != nil { + return e.legacyValidatorSetAtHeightFunc(int64(height)) + } + return e.getValidatorsAtHeight(int64(height)) +} + func (e *Executor) sequencerSetUpdates(height uint64) ([][]byte, error) { seqHash, err := e.sequencerCaller.SequencerSetVerifyHash(nil) if err != nil { @@ -99,19 +121,7 @@ func (e *Executor) updateSequencerSet(height uint64) ([][]byte, error) { _, isSequencer := e.seqTmKeySet[tmPKBz] if !e.isSequencer && isSequencer { - e.logger.Info("I am a sequencer, start to launch syncer") - if e.syncer == nil { - syncer, err := e.newSyncerFunc() - if err != nil { - e.logger.Error("failed to create syncer", "error", err) - return nil, err - } - e.syncer = syncer - e.l1MsgReader = syncer // syncer works as l1MsgReader - e.syncer.Start() - } else { - go e.syncer.Start() - } + e.logger.Info("I am a sequencer") } else if e.isSequencer && !isSequencer { // as the derivation always need the syncer running, it should not be stopped diff --git a/node/derivation/config.go b/node/derivation/config.go index a3f194ba8..441a1e697 100644 --- a/node/derivation/config.go +++ b/node/derivation/config.go @@ -179,11 +179,6 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { } } - legacyValidatorMode := ctx.GlobalBool(flags.LegacyValidatorMode.Name) - if legacyValidatorMode { - log.Warn("--validator is deprecated; use --derivation.verify-mode=layer1") - c.VerifyMode = VerifyModeLayer1 - } if ctx.GlobalIsSet(flags.DerivationVerifyMode.Name) { c.VerifyMode = ctx.GlobalString(flags.DerivationVerifyMode.Name) } diff --git a/node/derivation/config_test.go b/node/derivation/config_test.go index 4148c0c96..b72819bc7 100644 --- a/node/derivation/config_test.go +++ b/node/derivation/config_test.go @@ -42,31 +42,6 @@ func TestVerifyMode_AcceptsExplicitModes(t *testing.T) { } } -func TestVerifyMode_LegacyValidatorAlias(t *testing.T) { - cfg := DefaultConfig() - if err := cfg.SetCliContext(newVerifyModeTestContext(t, map[string]string{ - flags.LegacyValidatorMode.Name: "true", - })); err != nil { - t.Fatalf("legacy validator alias rejected: %v", err) - } - if cfg.VerifyMode != VerifyModeLayer1 { - t.Fatalf("legacy validator alias resolved to %q, want %q", cfg.VerifyMode, VerifyModeLayer1) - } -} - -func TestVerifyMode_ExplicitModeOverridesLegacyValidatorAlias(t *testing.T) { - cfg := DefaultConfig() - if err := cfg.SetCliContext(newVerifyModeTestContext(t, map[string]string{ - flags.LegacyValidatorMode.Name: "true", - flags.DerivationVerifyMode.Name: VerifyModeLocal, - })); err != nil { - t.Fatalf("explicit verify-mode rejected: %v", err) - } - if cfg.VerifyMode != VerifyModeLocal { - t.Fatalf("explicit verify-mode resolved to %q, want %q", cfg.VerifyMode, VerifyModeLocal) - } -} - func TestVerifyMode_RejectsUnknown(t *testing.T) { // "hybrid" was the old default; ensure post-removal it's rejected so // stale operator configs fail loud rather than silently falling back to @@ -150,7 +125,6 @@ func newVerifyModeTestContext(t *testing.T, values map[string]string) *cli.Conte flagSet := flag.NewFlagSet(t.Name(), flag.ContinueOnError) for _, f := range []cli.Flag{ - flags.LegacyValidatorMode, flags.DerivationVerifyMode, flags.MetricsPort, flags.L1BeaconAddr, diff --git a/node/flags/flags.go b/node/flags/flags.go index e6ed45f78..6d7277ab1 100644 --- a/node/flags/flags.go +++ b/node/flags/flags.go @@ -144,10 +144,10 @@ var ( EnvVar: prefixEnvVar("TDM_CONFIG"), } - DevSequencer = &cli.BoolFlag{ - Name: "dev-sequencer", - Usage: "explicitly specify that running as a sequencer. If it enables, the tendermint validator/batch params won't be changed no matter what happens to staking/gov contacts. Only use in dev/test mode", - EnvVar: prefixEnvVar("DEV_SEQUENCER"), + StaticValidatorTmKeys = cli.StringSliceFlag{ + Name: "static-validator-tm-key", + Usage: "Tendermint ed25519 validator public key (32-byte hex); repeat for every network validator", + EnvVar: prefixEnvVar("STATIC_VALIDATOR_TM_KEYS"), } MockEnabled = &cli.BoolFlag{ @@ -156,12 +156,6 @@ var ( EnvVar: prefixEnvVar("MOCK_SEQUENCER"), } - LegacyValidatorMode = cli.BoolFlag{ - Name: "validator", - Usage: "Deprecated compatibility alias for --derivation.verify-mode=layer1", - EnvVar: prefixEnvVar("VALIDATOR"), - } - // derivation RollupContractAddress = cli.StringFlag{ Name: "derivation.rollupAddress", @@ -401,10 +395,9 @@ var Flags = []cli.Flag{ DBCache, DBFreezer, - DevSequencer, + StaticValidatorTmKeys, TendermintConfigPath, MockEnabled, - LegacyValidatorMode, // derivation RollupContractAddress, From dea8882d03f6429dfa41da0f5f922b23e8166fb2 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:40:49 +0800 Subject: [PATCH 05/38] feat(batch): bootstrap from canonical static batches --- common/batch/batch_cache.go | 351 +++++-- .../batch/batch_cache_genesis_header_test.go | 10 +- common/batch/batch_cache_test.go | 9 +- common/batch/batch_header.go | 20 +- common/batch/batch_header_zero_test.go | 36 + common/batch/batch_query.go | 989 +++++++++++++----- common/batch/batch_query_test.go | 129 +++ common/batch/batch_restart_test.go | 492 +-------- common/batch/batch_storage_test.go | 2 +- common/batch/canonical_bootstrap_test.go | 386 +++++++ common/batch/commit_test.go | 19 +- common/batch/config.go | 39 + common/batch/config_test.go | 36 + common/batch/helpers_test.go | 9 + common/batch/interfaces.go | 21 +- common/batch/l2_gov.go | 51 +- common/batch/snapshot.go | 101 ++ 17 files changed, 1793 insertions(+), 907 deletions(-) create mode 100644 common/batch/batch_header_zero_test.go create mode 100644 common/batch/batch_query_test.go create mode 100644 common/batch/canonical_bootstrap_test.go create mode 100644 common/batch/config.go create mode 100644 common/batch/config_test.go create mode 100644 common/batch/snapshot.go diff --git a/common/batch/batch_cache.go b/common/batch/batch_cache.go index 74b987a70..3ead3194c 100644 --- a/common/batch/batch_cache.go +++ b/common/batch/batch_cache.go @@ -18,6 +18,7 @@ import ( "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/eth" "github.com/morph-l2/go-ethereum/log" + "github.com/morph-l2/go-ethereum/rpc" "morph-l2/common/blob" ) @@ -69,11 +70,11 @@ type BatchCache struct { l2Clients L2MultiClient rollupContract RollupBatchReader l2Gov L2GovCaller + l1Snapshot *confirmedL1Snapshot // config - batchTimeOut uint64 - blockInterval uint64 - maxBlobCount int + batchConfig BatchConfig + maxBlobCount int // replayL1CommittedBatches is true while InitAndSyncFromRollup is rebuilding committed batches from L2. replayL1CommittedBatches atomic.Bool @@ -94,6 +95,7 @@ func NewBatchCache( isBatchUpgraded func(uint64) bool, isBatchV2Upgraded func(uint64) bool, maxBlobCount int, + batchConfig BatchConfig, l1Client L1HeaderClient, l2Clients L2MultiClient, rollupContract RollupBatchReader, @@ -143,22 +145,32 @@ func NewBatchCache( rollupContract: rollupContract, l2Gov: l2Gov, batchStorage: NewBatchStorage(ldb), + batchConfig: batchConfig, maxBlobCount: maxBlobCount, } } func (bc *BatchCache) Init() error { - err := bc.updateBatchConfigFromGov() - if err != nil { + bc.initMu.Lock() + defer bc.initMu.Unlock() + return bc.withConfirmedL1Snapshot(bc.initLocked) +} + +func (bc *BatchCache) initLocked() error { + if err := bc.batchConfig.Validate(); err != nil { return err } + log.Info("Using static batch config", + "block_interval_blocks", bc.batchConfig.BlockInterval, + "timeout_seconds", bc.batchConfig.Timeout, + "config_hash", bc.batchConfig.Hash()) ci, fi, err := bc.getBatchStatusFromContract() if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } - headerBytes, err := bc.getLastFinalizeBatchHeaderFromRollupByIndex(fi.Uint64()) + headerBytes, err := bc.getCanonicalCommittedBatchHeaderByIndex(fi.Uint64()) if err != nil { - return fmt.Errorf("get last finalize batch header err: %w", err) + return fmt.Errorf("get canonical finalized batch header err: %w", err) } // Initialize BatchCache parent batch information @@ -169,12 +181,59 @@ func (bc *BatchCache) Init() error { } lastPackedBlockHeight, err := headerBytes.LastBlockNumber() if err != nil { - store, err := bc.rollupContract.BatchDataStore(nil, fi) + store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) if err != nil { return err } lastPackedBlockHeight = store.BlockNumber.Uint64() } + store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) + if err != nil { + return fmt.Errorf("read finalized batch %d metadata: %w", fi.Uint64(), err) + } + if store.BlockNumber == nil || store.BlockNumber.Uint64() != lastPackedBlockHeight { + return fmt.Errorf("finalized batch %d L2 block mismatch: header=%d store=%v", fi.Uint64(), lastPackedBlockHeight, store.BlockNumber) + } + finalizedRoot, err := bc.rollupContract.FinalizedStateRoots(bc.snapshotCallOpts(), fi) + if err != nil { + return fmt.Errorf("read finalized state root for batch %d: %w", fi.Uint64(), err) + } + if common.Hash(finalizedRoot) != prevStateRoot { + return fmt.Errorf("finalized batch %d state root mismatch: header=%s rollup=%s", fi.Uint64(), prevStateRoot, common.Hash(finalizedRoot)) + } + l2Anchor, err := bc.l2Clients.BlockByNumber(context.Background(), new(big.Int).SetUint64(lastPackedBlockHeight)) + if err != nil { + return fmt.Errorf("read finalized L2 anchor block %d: %w", lastPackedBlockHeight, err) + } + if l2Anchor == nil { + return fmt.Errorf("read finalized L2 anchor block %d: nil block", lastPackedBlockHeight) + } + if l2Anchor.Root() != prevStateRoot { + return fmt.Errorf("finalized L2 anchor state root mismatch: block=%d header=%s l2=%s", lastPackedBlockHeight, prevStateRoot, l2Anchor.Root()) + } + l2AnchorHash := l2Anchor.Hash() + withdrawalRoot, err := headerBytes.WithdrawalRoot() + if err != nil { + return fmt.Errorf("read finalized withdrawal root: %w", err) + } + anchorWithdrawalRoot, err := bc.l2Gov.GetTreeRoot(&bind.CallOpts{Context: bc.ctx, BlockNumber: new(big.Int).SetUint64(lastPackedBlockHeight)}) + if err != nil { + return fmt.Errorf("read L2 withdrawal root at finalized anchor %d: %w", lastPackedBlockHeight, err) + } + if common.Hash(anchorWithdrawalRoot) != withdrawalRoot { + return fmt.Errorf("finalized withdrawal root mismatch: block=%d header=%s l2=%s", lastPackedBlockHeight, withdrawalRoot, common.Hash(anchorWithdrawalRoot)) + } + recheckedL2Anchor, err := bc.l2Clients.BlockByNumber(context.Background(), new(big.Int).SetUint64(lastPackedBlockHeight)) + if err != nil { + return fmt.Errorf("re-read finalized L2 anchor block %d: %w", lastPackedBlockHeight, err) + } + if recheckedL2Anchor == nil || recheckedL2Anchor.Hash() != l2AnchorHash { + actual := common.Hash{} + if recheckedL2Anchor != nil { + actual = recheckedL2Anchor.Hash() + } + return fmt.Errorf("finalized L2 anchor changed during bootstrap: block=%d expected=%s actual=%s", lastPackedBlockHeight, l2AnchorHash, actual) + } totalL1MessagePopped, err := headerBytes.TotalL1MessagePopped() if err != nil { return fmt.Errorf("get total l1 message popped err: %w", err) @@ -184,6 +243,7 @@ func (bc *BatchCache) Init() error { bc.prevStateRoot = prevStateRoot bc.lastPackedBlockHeight = lastPackedBlockHeight bc.currentBlockNumber = lastPackedBlockHeight + bc.currentBlockHash = l2AnchorHash bc.totalL1MessagePopped = totalL1MessagePopped bc.mu.Unlock() log.Info("Start assemble batch", "start batch", fi.Uint64(), "end batch", ci.Uint64()) @@ -205,30 +265,33 @@ func (bc *BatchCache) setInitialized() { func (bc *BatchCache) InitFromRollupByRange() error { bc.initMu.Lock() defer bc.initMu.Unlock() - if bc.isInitialized() { + return bc.withConfirmedL1Snapshot(func() error { + if bc.isInitialized() { + return nil + } + if err := bc.initLocked(); err != nil { + return err + } + if err := bc.assembleUnFinalizeBatchHeaderFromL2Blocks(); err != nil { + return err + } + bc.setInitialized() + log.Info("Initialized batch cache success") return nil - } - err := bc.Init() - if err != nil { - return err - } - err = bc.assembleUnFinalizeBatchHeaderFromL2Blocks() - if err != nil { - return err - } - bc.setInitialized() - log.Info("Initialized batch cache success") - return nil + }) } func (bc *BatchCache) InitAndSyncFromDatabase() error { bc.initMu.Lock() defer bc.initMu.Unlock() + return bc.withConfirmedL1Snapshot(bc.initAndSyncFromDatabaseLocked) +} + +func (bc *BatchCache) initAndSyncFromDatabaseLocked() error { if bc.isInitialized() { return nil } - err := bc.updateBatchConfigFromGov() - if err != nil { + if err := bc.batchConfig.Validate(); err != nil { return err } ci, fi, err := bc.getBatchStatusFromContract() @@ -251,9 +314,11 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { maxIndex = idx } } - // check batch hash with the batch that already rollup by submitter - for i := fi.Uint64(); i <= ci.Uint64(); i++ { - batchHash, err := bc.rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(i)) + // Sealed storage contains batches after the finalized anchor; the anchor + // itself is reconstructed from canonical L1 and is never a local sealed + // checkpoint. Validate only the committed, unfinalized suffix. + for i := fi.Uint64() + 1; i > fi.Uint64() && i <= ci.Uint64(); i++ { + batchHash, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), new(big.Int).SetUint64(i)) if err != nil { return err } @@ -290,7 +355,7 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { "commitIndex", ci.Uint64(), "finalizeIndex", fi.Uint64()) return bc.deleteBatchStorageAndInitFromRollupLocked() } - store, err := bc.rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(latestBatchIndex)) + store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), new(big.Int).SetUint64(latestBatchIndex)) if err != nil { log.Error("Failed to load latest batch index from rollup", "error", err, @@ -317,7 +382,7 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { func (bc *BatchCache) InitAndSyncFromRollup() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.initAndSyncFromRollupLocked() + return bc.withConfirmedL1Snapshot(bc.initAndSyncFromRollupLocked) } func (bc *BatchCache) initAndSyncFromRollupLocked() error { @@ -327,7 +392,7 @@ func (bc *BatchCache) initAndSyncFromRollupLocked() error { bc.replayL1CommittedBatches.Store(true) defer bc.replayL1CommittedBatches.Store(false) - err := bc.Init() + err := bc.initLocked() if err != nil { return err } @@ -375,23 +440,8 @@ func (bc *BatchCache) LatestBatchIndex() (uint64, error) { return bc.parentBatchHeader.BatchIndex() } -func (bc *BatchCache) updateBatchConfigFromGov() error { - interval, err := bc.l2Gov.BatchBlockInterval(nil) - if err != nil { - return err - } - timeout, err := bc.l2Gov.BatchTimeout(nil) - if err != nil { - return err - } - bc.batchTimeOut = timeout.Uint64() - bc.blockInterval = interval.Uint64() - log.Info("Update batch config success", "interval", interval.Uint64(), "timeout", timeout.Uint64()) - return nil -} - func (bc *BatchCache) checkBatchHashCorrect(batchIndex *big.Int, batchHash common.Hash) (bool, error) { - commitBatchHash, err := bc.rollupContract.CommittedBatches(nil, batchIndex) + commitBatchHash, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), batchIndex) if err != nil { return false, err } @@ -406,11 +456,11 @@ func (bc *BatchCache) checkBatchHashCorrect(batchIndex *big.Int, batchHash commo } func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { - latestCommitBatchIndex, err := bc.rollupContract.LastCommittedBatchIndex(nil) + latestCommitBatchIndex, err := bc.rollupContract.LastCommittedBatchIndex(bc.snapshotCallOpts()) if err != nil { return nil, nil, err } - lastFinalizedBatchIndex, err := bc.rollupContract.LastFinalizedBatchIndex(nil) + lastFinalizedBatchIndex, err := bc.rollupContract.LastFinalizedBatchIndex(bc.snapshotCallOpts()) if err != nil { return nil, nil, err } @@ -419,11 +469,11 @@ func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { func (bc *BatchCache) getBatchBlockRange(batchIndex *big.Int) (uint64, uint64, error) { preIndex := new(big.Int).Sub(batchIndex, big.NewInt(1)) - preBatchStorage, err := bc.rollupContract.BatchDataStore(nil, preIndex) + preBatchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), preIndex) if err != nil { return 0, 0, err } - batchStorage, err := bc.rollupContract.BatchDataStore(nil, batchIndex) + batchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), batchIndex) if err != nil { return 0, 0, err } @@ -435,7 +485,7 @@ func (bc *BatchCache) getUnFinalizeBlockRange() (uint64, uint64, *big.Int, error if err != nil { return 0, 0, nil, err } - finalizeBatchStorage, err := bc.rollupContract.BatchDataStore(nil, fi) + finalizeBatchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) if err != nil { return 0, 0, nil, err } @@ -666,7 +716,6 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // SealBatch seals the currently accumulated batch, generates batch header and stores to sealedBatches // Parameters: -// - sequencerSetVerifyHash: sequencer set verification hash (obtained from L1 contract) // - blockTimestamp: current block timestamp (used to determine batch version) // // Returns: @@ -680,7 +729,7 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // replayCommittedBatchIndex, when non-nil, is the rollup batch index being re-sealed while syncing // from L1 (InitAndSyncFromRollup). After V2 multi-blob, blob capacity is capped at replayProtocolMaxBlobs // (6), not max_blob_count, without querying L1 CommitBatch logs. -func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { +func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { bc.mu.Lock() defer bc.mu.Unlock() @@ -722,7 +771,7 @@ func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, rep ) // Create batch header - batchHeader := bc.createBatchHeader(batchDataHash, sidecar, crypto.Keccak256Hash(sequencerSets), blockTimestamp) + batchHeader := bc.createBatchHeader(batchDataHash, sidecar, blockTimestamp) // Calculate batch hash batchHash, err := batchHeader.Hash() @@ -755,26 +804,21 @@ func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, rep } blockContexts := hexutil.Bytes(blockContextsData) - // Convert sequencerSetVerifyHash to bytes - currentSequencerSetBytes := hexutil.Bytes(sequencerSets) - // Get L1 message count from batch data numL1Messages := bc.batchData.l1TxNum // Store sealed batch information as RPCRollupBatch sealedBatch := ð.RPCRollupBatch{ - Version: uint(version), - Hash: batchHash, - ParentBatchHeader: parentBatchHeaderBytes, - BlockContexts: blockContexts, - CurrentSequencerSetBytes: currentSequencerSetBytes, - PrevStateRoot: bc.prevStateRoot, - PostStateRoot: bc.postStateRoot, - WithdrawRoot: bc.withdrawRoot, - LastBlockNumber: bc.lastPackedBlockHeight, - NumL1Messages: numL1Messages, - Sidecar: *sidecar, - Signatures: []eth.RPCBatchSignature{}, + Version: uint(version), + Hash: batchHash, + ParentBatchHeader: parentBatchHeaderBytes, + BlockContexts: blockContexts, + PrevStateRoot: bc.prevStateRoot, + PostStateRoot: bc.postStateRoot, + WithdrawRoot: bc.withdrawRoot, + LastBlockNumber: bc.lastPackedBlockHeight, + NumL1Messages: numL1Messages, + Sidecar: *sidecar, } bc.sealedBatches[batchIndex] = sealedBatch // Store batch header copy @@ -915,7 +959,7 @@ func (bc *BatchCache) handleBatchSealing(blockTimestamp uint64, sealBlobCap int, } // createBatchHeader creates BatchHeader -func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, sequencerSetVerifyHash common.Hash, blockTimestamp uint64) BatchHeaderBytes { +func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, blockTimestamp uint64) BatchHeaderBytes { blobHashes := []common.Hash{blob.EmptyVersionedHash} if sidecar != nil && len(sidecar.Blobs) > 0 { blobHashes = sidecar.BlobHashes() @@ -942,7 +986,7 @@ func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes. PrevStateRoot: bc.prevStateRoot, PostStateRoot: bc.postStateRoot, WithdrawalRoot: bc.withdrawRoot, - SequencerSetVerifyHash: sequencerSetVerifyHash, + SequencerSetVerifyHash: common.Hash{}, ParentBatchHash: parentBatchHash, } @@ -1114,10 +1158,6 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( } } - sequencerSet, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return nil, fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) - } // Get the last block's timestamp for packing lastBlock, err := bc.l2Clients.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) if err != nil { @@ -1126,7 +1166,7 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(sequencerSet, blockTimestamp, replayCommittedBatchIndex) + batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, replayCommittedBatchIndex) if err != nil { return nil, fmt.Errorf("failed to seal batch: %w", err) } @@ -1180,22 +1220,22 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract + // This ensures batch is sealed before exceeding the configured static timeout. timeout := false - if bc.batchTimeOut > 0 { + if bc.batchConfig.Timeout > 0 { elapsedTime := nowBlockTime - startBlockTime - if elapsedTime >= bc.batchTimeOut { + if elapsedTime >= bc.batchConfig.Timeout { timeout = true log.Info("Batch timeout reached, must seal batch", "startBlock", startBlockNum, "currentBlock", blockNum, - "elapsedTime", elapsedTime, "batchTimeOut", bc.batchTimeOut) + "elapsedTime", elapsedTime, "batchTimeOut", bc.batchConfig.Timeout) } } // Check if we need to seal batch due to capacity, block interval, or timeout // check ensures batch is sealed before exceeding the maximum timeout - if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { + if exceeded || (bc.batchConfig.BlockInterval > 0 && (blockNum-startBlockNum+1) == bc.batchConfig.BlockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum-1, "exceeded", exceeded, "timeout", timeout) - batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(callOpts, ci) + batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(ci) if err != nil { return err } @@ -1225,18 +1265,14 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { return nil } -func (bc *BatchCache) SealBatchAndCheck(callOpts *bind.CallOpts, ci *big.Int) (common.Hash, bool, uint64, error) { - sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return common.Hash{}, false, 0, err - } +func (bc *BatchCache) SealBatchAndCheck(ci *big.Int) (common.Hash, bool, uint64, error) { lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) + batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, nil) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to seal batch: %w", err) } @@ -1374,10 +1410,15 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { callOpts := &bind.CallOpts{ Context: bc.ctx, } - endBlockNum, err := bc.l2Clients.BlockNumber(bc.ctx) + safeHead, err := bc.l2Clients.BlockByNumber(bc.ctx, big.NewInt(int64(rpc.SafeBlockNumber))) if err != nil { - return err + return fmt.Errorf("get fixed L2 safe head: %w", err) + } + if safeHead == nil { + return errors.New("get fixed L2 safe head: nil block") } + endBlockNum := safeHead.NumberU64() + safeHeadHash := safeHead.Hash() if endBlockNum < bc.currentBlockNumber { return fmt.Errorf("has reorg, should check block status current %v, now %v", bc.currentBlockNumber, endBlockNum) } @@ -1387,17 +1428,10 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { } version, _ := bc.parentBatchHeader.Version() if version < 1 { - parentIndex, err := bc.parentBatchHeader.BatchIndex() - if err != nil { - log.Error("failed to get block index", "err", err) - return err - } - store, err := bc.rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(parentIndex)) - if err != nil { - log.Error("failed to get batch store", "err", err) - return err - } - startBlockNum = store.BlockNumber.Uint64() + // V0 headers do not encode lastBlockNumber. Bootstrap already resolved + // and verified it from BatchDataStore at the fixed L1 snapshot, so retain + // that pinned value instead of issuing a new latest-state getter here. + startBlockNum = bc.lastPackedBlockHeight } else { startBlockNum, err = bc.parentBatchHeader.LastBlockNumber() if err != nil { @@ -1411,11 +1445,25 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { return fmt.Errorf("invalid block number") } startBlockNum++ + if currentBlockNum == endBlockNum { + return bc.verifyFixedL2Head(endBlockNum, safeHeadHash) + } + priorBlock, err := bc.l2Clients.BlockByNumber(bc.ctx, new(big.Int).SetUint64(currentBlockNum)) + if err != nil { + return fmt.Errorf("read L2 bootstrap parent block %d: %w", currentBlockNum, err) + } + if priorBlock == nil || priorBlock.NumberU64() != currentBlockNum { + return fmt.Errorf("L2 gap at bootstrap parent: expected=%d got=%v", currentBlockNum, blockNumberOrNil(priorBlock)) + } + previousBlockHash := priorBlock.Hash() // Get start block once to avoid repeated queries startBlock, err := bc.l2Clients.BlockByNumber(bc.ctx, big.NewInt(int64(startBlockNum))) if err != nil { return fmt.Errorf("failed to get start block %d: %w", startBlockNum, err) } + if startBlock == nil || startBlock.NumberU64() != startBlockNum { + return fmt.Errorf("L2 gap at first bootstrap block: expected=%d got=%v", startBlockNum, blockNumberOrNil(startBlock)) + } startBlockTime := startBlock.Time() progressState := batchPackProgressState{} @@ -1438,35 +1486,44 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { if err != nil { return fmt.Errorf("failed to get block %d: %w", blockNum, err) } + if nowBlock == nil || nowBlock.NumberU64() != blockNum { + return fmt.Errorf("L2 gap while packing bootstrap range: expected=%d got=%v", blockNum, blockNumberOrNil(nowBlock)) + } nowBlockTime := nowBlock.Time() + if nowBlock.Hash() != bc.currentProposalHash() { + return fmt.Errorf("L2 block changed while packing bootstrap range: block=%d", blockNum) + } + if nowBlock.ParentHash() != previousBlockHash { + return fmt.Errorf("L2 parent hash discontinuity during bootstrap: block=%d expectedParent=%s actualParent=%s", blockNum, previousBlockHash, nowBlock.ParentHash()) + } + previousBlockHash = nowBlock.Hash() bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract + // This ensures batch is sealed before exceeding the configured static timeout. timeout := false - if bc.batchTimeOut > 0 { + if bc.batchConfig.Timeout > 0 { elapsedTime := nowBlockTime - startBlockTime - if elapsedTime >= bc.batchTimeOut { + if elapsedTime >= bc.batchConfig.Timeout { timeout = true log.Info("Batch timeout reached, must seal batch", "startBlock", startBlockNum, "currentBlock", blockNum, - "elapsedTime", elapsedTime, "batchTimeOut", bc.batchTimeOut) + "elapsedTime", elapsedTime, "batchTimeOut", bc.batchConfig.Timeout) } } // Check if we need to seal batch due to capacity, block interval, or timeout // check ensures batch is sealed before exceeding the maximum timeout - if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { + if exceeded || (bc.batchConfig.BlockInterval > 0 && (blockNum-startBlockNum+1) == bc.batchConfig.BlockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum, "exceeded", exceeded, "timeout", timeout) - sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) - } lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } + if lastBlock == nil || lastBlock.NumberU64() != bc.lastPackedBlockHeight { + return fmt.Errorf("L2 gap at last packed block: expected=%d got=%v", bc.lastPackedBlockHeight, blockNumberOrNil(lastBlock)) + } blockTimestamp := lastBlock.Time() - batchIndex, _, _, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) + batchIndex, _, _, err := bc.SealBatch(blockTimestamp, nil) if err != nil { return fmt.Errorf("failed to seal batch: %w", err) } @@ -1479,6 +1536,9 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { if err != nil { return fmt.Errorf("failed to get start block %d: %w", startBlockNum, err) } + if startBlock == nil || startBlock.NumberU64() != startBlockNum { + return fmt.Errorf("L2 gap after sealed bootstrap batch: expected=%d got=%v", startBlockNum, blockNumberOrNil(startBlock)) + } startBlockTime = startBlock.Time() progressState = batchPackProgressState{} } @@ -1488,6 +1548,34 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { return fmt.Errorf("failed to pack block %d: %w", blockNum, err) } } + return bc.verifyFixedL2Head(endBlockNum, safeHeadHash) +} + +func blockNumberOrNil(block *ethtypes.Block) interface{} { + if block == nil { + return nil + } + return block.NumberU64() +} + +func (bc *BatchCache) currentProposalHash() common.Hash { + bc.mu.RLock() + defer bc.mu.RUnlock() + return bc.currentBlockHash +} + +func (bc *BatchCache) verifyFixedL2Head(number uint64, expected common.Hash) error { + head, err := bc.l2Clients.BlockByNumber(bc.ctx, new(big.Int).SetUint64(number)) + if err != nil { + return fmt.Errorf("re-read fixed L2 safe head %d: %w", number, err) + } + if head == nil || head.Hash() != expected { + actual := common.Hash{} + if head != nil { + actual = head.Hash() + } + return fmt.Errorf("L2 safe head changed during bootstrap: number=%d expected=%s actual=%s", number, expected, actual) + } return nil } @@ -1510,13 +1598,13 @@ func (bc *BatchCache) logBatchPackingProgress(startBlockNum, currentBlockNum, st } timePercent := uint64(0) - if bc.batchTimeOut > 0 { - timePercent = progressPercent(elapsedTime, bc.batchTimeOut) + if bc.batchConfig.Timeout > 0 { + timePercent = progressPercent(elapsedTime, bc.batchConfig.Timeout) } blockPercent := uint64(0) - if bc.blockInterval > 0 { - blockPercent = progressPercent(packedBlocks, bc.blockInterval) + if bc.batchConfig.BlockInterval > 0 { + blockPercent = progressPercent(packedBlocks, bc.batchConfig.BlockInterval) } blobPercent := uint64(0) @@ -1585,7 +1673,40 @@ func maxUint64(values ...uint64) uint64 { func (bc *BatchCache) DeleteBatchStorageAndInitFromRollup() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.withConfirmedL1Snapshot(bc.deleteBatchStorageAndInitFromRollupLocked) +} + +// ResetCanonicalBootstrap discards every locally reconstructed/sealed batch and +// clears all in-memory progress. It is used only when cold-start validation +// fails after writes may already have occurred, so the next attempt cannot +// continue from a partial or reorged checkpoint. +func (bc *BatchCache) ResetCanonicalBootstrap() error { + bc.initMu.Lock() + defer bc.initMu.Unlock() + + if err := bc.batchStorage.DeleteAllSealedBatches(); err != nil { + if forceErr := bc.batchStorage.ForceDeleteAllSealedBatches(); forceErr != nil { + return fmt.Errorf("reset canonical bootstrap storage (normal error: %v): %w", err, forceErr) + } + } + + bc.mu.Lock() + defer bc.mu.Unlock() + bc.initDone = false + bc.sealedBatches = make(map[uint64]*eth.RPCRollupBatch) + bc.sealedBatchHeaders = make(map[uint64]*BatchHeaderBytes) + bc.parentBatchHeader = nil + bc.prevStateRoot = common.Hash{} + bc.batchData = nil + bc.totalL1MessagePopped = 0 + bc.postStateRoot = common.Hash{} + bc.withdrawRoot = common.Hash{} + bc.lastPackedBlockHeight = 0 + bc.currentBlockNumber = 0 + bc.currentBlockHash = common.Hash{} + bc.ClearCurrent() + bc.replayL1CommittedBatches.Store(false) + return nil } func (bc *BatchCache) deleteBatchStorageAndInitFromRollupLocked() error { diff --git a/common/batch/batch_cache_genesis_header_test.go b/common/batch/batch_cache_genesis_header_test.go index 2b984e8f3..6a8db254f 100644 --- a/common/batch/batch_cache_genesis_header_test.go +++ b/common/batch/batch_cache_genesis_header_test.go @@ -19,10 +19,6 @@ var ( globalGenesisBatchHeader *BatchHeaderBytes globalGenesisBatchHeaderErr error globalGenesisBatchHeaderOnce sync.Once - - // Global overrides for cache batch config in tests (instead of updateBatchConfigFromGov). - globalBatchTimeoutForTest uint64 = 10000000 - globalBlockIntervalForTest uint64 = 10000 ) func ensureGlobalGenesisBatchHeader() error { @@ -55,9 +51,6 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { if globalGenesisBatchHeader == nil { return ErrKeyNotFound } - // Use global test knobs instead of querying gov config from chain. - cache.batchTimeOut = globalBatchTimeoutForTest - cache.blockInterval = globalBlockIntervalForTest headerCopy := make(BatchHeaderBytes, len(*globalGenesisBatchHeader)) copy(headerCopy, *globalGenesisBatchHeader) cache.parentBatchHeader = &headerCopy @@ -86,9 +79,10 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { } func TestBatchCacheInitWithGlobalGenesisHeader(t *testing.T) { + requireBatchIntegration(t) testDB := openTestKV(t) a := func(uint64) bool { return true } - cache := NewBatchCache(nil, a, 3, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, a, 3, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex done := make(chan error, 1) diff --git a/common/batch/batch_cache_test.go b/common/batch/batch_cache_test.go index 3965fa4aa..72456b382 100644 --- a/common/batch/batch_cache_test.go +++ b/common/batch/batch_cache_test.go @@ -26,8 +26,9 @@ func init() { } func TestBatchCacheInitServer(t *testing.T) { + requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex @@ -59,15 +60,17 @@ func TestBatchCacheInitServer(t *testing.T) { } func TestBatchCacheInit(t *testing.T) { + requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitAndSyncFromRollup() require.NoError(t, err) } func TestBatchCacheInitByBlockRange(t *testing.T) { + requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) } diff --git a/common/batch/batch_header.go b/common/batch/batch_header.go index 71faaf9fd..e5f1fbc4d 100644 --- a/common/batch/batch_header.go +++ b/common/batch/batch_header.go @@ -42,7 +42,25 @@ func (b BatchHeaderBytes) validate() error { switch version { case BatchHeaderVersion0: if len(b) != expectedLengthV0 { - return ErrInvalidBatchHeaderLength + // Frozen legacy V0 headers append one 32-byte skipped-message + // bitmap word per 256 popped messages. Current V0 headers are the + // fixed 249-byte form, so accept both exact historical encodings. + if len(b) < expectedLengthV0 { + return ErrInvalidBatchHeaderLength + } + l1MessagePopped := binary.BigEndian.Uint64(b[9:17]) + bitmapWords := l1MessagePopped / 256 + if l1MessagePopped%256 != 0 { + bitmapWords++ + } + maxInt := uint64(^uint(0) >> 1) + if bitmapWords > (maxInt-expectedLengthV0)/32 { + return ErrInvalidBatchHeaderLength + } + legacyLength := expectedLengthV0 + int(bitmapWords)*32 + if len(b) != legacyLength { + return ErrInvalidBatchHeaderLength + } } case BatchHeaderVersion1: if len(b) != expectedLengthV1 { diff --git a/common/batch/batch_header_zero_test.go b/common/batch/batch_header_zero_test.go new file mode 100644 index 000000000..b14f69950 --- /dev/null +++ b/common/batch/batch_header_zero_test.go @@ -0,0 +1,36 @@ +package batch + +import ( + "testing" + + "github.com/morph-l2/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestNewBatchHeaderSequencerSetVerifyHashIsZeroForAllVersions(t *testing.T) { + tests := []struct { + name string + upgraded bool + v2 bool + wantLen int + }{ + {name: "v0", wantLen: expectedLengthV0}, + {name: "v1", upgraded: true, wantLen: expectedLengthV1}, + {name: "v2", upgraded: true, v2: true, wantLen: expectedLengthV2}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cache := &BatchCache{ + isBatchUpgraded: func(uint64) bool { return test.upgraded }, + isBatchV2Upgraded: func(uint64) bool { return test.v2 }, + } + header := cache.createBatchHeader(common.Hash{1}, nil, 1) + verifyHash, err := header.SequencerSetVerifyHash() + require.NoError(t, err) + require.Equal(t, common.Hash{}, verifyHash) + require.Equal(t, BatchHeaderBytes(make([]byte, 32)), header[185:217]) + require.Len(t, header, test.wantLen) + }) + } +} diff --git a/common/batch/batch_query.go b/common/batch/batch_query.go index 21d463294..ffad39280 100644 --- a/common/batch/batch_query.go +++ b/common/batch/batch_query.go @@ -2,349 +2,834 @@ package batch import ( "bytes" - "context" + "encoding/binary" "errors" "fmt" "math/big" + "sort" + "strings" "morph-l2/bindings/bindings" + "morph-l2/common/blob" "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" ) -// getLastFinalizeBatchHeaderFromRollupByIndex gets the batch header with the specified index from the rollup contract's FinalizeBatch event -// The finalizeBatch function only receives one parameter: batchHeader bytes, so it can be parsed directly from the transaction -// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found -func (bc *BatchCache) getLastFinalizeBatchHeaderFromRollupByIndex(index uint64) (*BatchHeaderBytes, error) { - // Get the current latest block height - latestBlock, err := bc.l1Client.BlockNumber(context.Background()) - if err != nil { - return nil, fmt.Errorf("failed to get latest block number: %w", err) +type canonicalCommitEvent struct { + batchIndex uint64 + batchHash common.Hash + raw ethtypes.Log +} + +type canonicalRevertEvent struct { + batchIndex uint64 + batchHash common.Hash + raw ethtypes.Log +} + +func logIdentityLess(a, b ethtypes.Log) bool { + if a.BlockNumber != b.BlockNumber { + return a.BlockNumber < b.BlockNumber + } + if a.TxIndex != b.TxIndex { + return a.TxIndex < b.TxIndex } + return a.Index < b.Index +} - const blockRange = uint64(10000) // Query 10000 blocks each time - var endBlock uint64 = latestBlock - var startBlock uint64 +// selectCanonicalCommit follows the shared resolver contract from spec 9.3: +// discard commits at/before the last revert and select the last remaining log +// whose hash equals committedBatches[index] at the fixed snapshot. +func selectCanonicalCommit( + index uint64, + expectedHash common.Hash, + commits []canonicalCommitEvent, + reverts []canonicalRevertEvent, +) (*canonicalCommitEvent, error) { + if expectedHash == (common.Hash{}) { + return nil, fmt.Errorf("batch %d has no canonical committed hash at snapshot", index) + } + sort.Slice(commits, func(i, j int) bool { return logIdentityLess(commits[i].raw, commits[j].raw) }) + sort.Slice(reverts, func(i, j int) bool { return logIdentityLess(reverts[i].raw, reverts[j].raw) }) - // Start from the latest height, query backwards 10000 blocks each time until data is found - for endBlock > 0 { - // Calculate the start block for this query - if endBlock >= blockRange { - startBlock = endBlock - blockRange + 1 - } else { - startBlock = 0 + var lastRevert *canonicalRevertEvent + for i := range reverts { + if reverts[i].batchIndex == index { + lastRevert = &reverts[i] } - - // Set query options - filterOpts := &bind.FilterOpts{ - Start: startBlock, - End: &endBlock, + } + var selected *canonicalCommitEvent + for i := range commits { + candidate := &commits[i] + if candidate.batchIndex != index || candidate.batchHash != expectedHash { + continue } - - // Query the FinalizeBatch event with the corresponding index from the rollup contract - finalizeEventIter, err := bc.rollupContract.FilterFinalizeBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) - if err != nil { - // If query fails, continue querying backwards - if startBlock == 0 { - break // Already queried to block 0, exit loop - } - endBlock = startBlock - 1 + if lastRevert != nil && !logIdentityLess(lastRevert.raw, candidate.raw) { continue } - defer func() { _ = finalizeEventIter.Close() }() - // Iterate through query results - for finalizeEventIter.Next() { - event := finalizeEventIter.Event - // Get transaction hash from event - txHash := event.Raw.TxHash + selected = candidate + } + if selected == nil { + return nil, fmt.Errorf("no canonical CommitBatch log for batch %d and hash %s", index, expectedHash) + } + return selected, nil +} - // Get transaction details - tx, _, err := bc.l1Client.TransactionByHash(context.Background(), txHash) - if err != nil { - continue // If getting transaction fails, try next event - } +// getCanonicalCommittedBatchHeaderByIndex recovers a complete header from the +// last canonical CommitBatch transaction at the already-fixed L1 snapshot. A +// FinalizeBatch transaction is deliberately never used as a header substitute. +func (bc *BatchCache) getCanonicalCommittedBatchHeaderByIndex(index uint64) (*BatchHeaderBytes, error) { + if bc.l1Snapshot == nil { + return nil, errors.New("canonical batch header lookup requires a confirmed L1 snapshot") + } + expectedRaw, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), new(big.Int).SetUint64(index)) + if err != nil { + return nil, fmt.Errorf("read committed batch %d at snapshot: %w", index, err) + } + expectedHash := common.Hash(expectedRaw) - // Parse finalizeBatch transaction data to get batchHeader - batchHeader, err := parseFinalizeBatchTxData(tx.Data()) - if err != nil { - continue // If parsing fails, try next event + commits, reverts, err := bc.collectCanonicalBatchEvents(index) + if err != nil { + return nil, err + } + selected, err := selectCanonicalCommit(index, expectedHash, commits, reverts) + if err != nil { + return nil, err + } + tx, pending, err := bc.l1Client.TransactionByHash(bc.ctx, selected.raw.TxHash) + if err != nil { + return nil, fmt.Errorf("load canonical batch %d transaction %s: %w", index, selected.raw.TxHash, err) + } + if tx == nil || pending { + return nil, fmt.Errorf("canonical batch %d transaction %s is missing or pending", index, selected.raw.TxHash) + } + header, err := bc.reconstructCommittedBatchHeader(index, expectedHash, tx) + if err != nil { + return nil, fmt.Errorf("reconstruct canonical batch %d from transaction %s: %w", index, selected.raw.TxHash, err) + } + return &header, nil +} + +func (bc *BatchCache) collectCanonicalBatchEvents(index uint64) ([]canonicalCommitEvent, []canonicalRevertEvent, error) { + const blockRange uint64 = 10_000 + var commits []canonicalCommitEvent + var reverts []canonicalRevertEvent + for start := uint64(0); ; { + end := start + blockRange - 1 + if end < start || end > bc.l1Snapshot.number { + end = bc.l1Snapshot.number + } + opts, err := bc.snapshotFilterOpts(start, end) + if err != nil { + return nil, nil, err + } + commitIter, err := bc.rollupContract.FilterCommitBatch(opts, []*big.Int{new(big.Int).SetUint64(index)}, nil) + if err != nil { + return nil, nil, fmt.Errorf("filter CommitBatch %d in L1 range [%d,%d]: %w", index, start, end, err) + } + for commitIter.Next() { + event := commitIter.Event + if event == nil || event.BatchIndex == nil || !event.BatchIndex.IsUint64() { + _ = commitIter.Close() + return nil, nil, fmt.Errorf("malformed CommitBatch event for batch %d", index) } + if event.BatchIndex.Uint64() != index || event.Raw.Removed || event.Raw.BlockNumber < start || event.Raw.BlockNumber > end { + _ = commitIter.Close() + return nil, nil, fmt.Errorf("non-canonical CommitBatch event returned for batch %d", index) + } + commits = append(commits, canonicalCommitEvent{ + batchIndex: event.BatchIndex.Uint64(), + batchHash: common.Hash(event.BatchHash), + raw: event.Raw, + }) + } + iterErr := commitIter.Error() + closeErr := commitIter.Close() + if iterErr != nil { + return nil, nil, fmt.Errorf("iterate CommitBatch %d in L1 range [%d,%d]: %w", index, start, end, iterErr) + } + if closeErr != nil { + return nil, nil, fmt.Errorf("close CommitBatch iterator for batch %d: %w", index, closeErr) + } - // Verify if batch index matches - batchIndex, err := batchHeader.BatchIndex() - if err != nil { - continue + opts, err = bc.snapshotFilterOpts(start, end) + if err != nil { + return nil, nil, err + } + revertIter, err := bc.rollupContract.FilterRevertBatch(opts, []*big.Int{new(big.Int).SetUint64(index)}, nil) + if err != nil { + return nil, nil, fmt.Errorf("filter RevertBatch %d in L1 range [%d,%d]: %w", index, start, end, err) + } + for revertIter.Next() { + event := revertIter.Event + if event == nil || event.BatchIndex == nil || !event.BatchIndex.IsUint64() { + _ = revertIter.Close() + return nil, nil, fmt.Errorf("malformed RevertBatch event for batch %d", index) } - if batchIndex == index { - return &batchHeader, nil + if event.BatchIndex.Uint64() != index || event.Raw.Removed || event.Raw.BlockNumber < start || event.Raw.BlockNumber > end { + _ = revertIter.Close() + return nil, nil, fmt.Errorf("non-canonical RevertBatch event returned for batch %d", index) } + reverts = append(reverts, canonicalRevertEvent{ + batchIndex: event.BatchIndex.Uint64(), + batchHash: common.Hash(event.BatchHash), + raw: event.Raw, + }) + } + iterErr = revertIter.Error() + closeErr = revertIter.Close() + if iterErr != nil { + return nil, nil, fmt.Errorf("iterate RevertBatch %d in L1 range [%d,%d]: %w", index, start, end, iterErr) + } + if closeErr != nil { + return nil, nil, fmt.Errorf("close RevertBatch iterator for batch %d: %w", index, closeErr) } - // Continue querying backwards - if endBlock < blockRange { - break // Already queried to block 0, exit loop + if end == bc.l1Snapshot.number { + break } - endBlock = startBlock - 1 + start = end + 1 } - - return nil, fmt.Errorf("failed to find last finalized batch header for batchIndex %d", index) + return commits, reverts, nil } -// parseFinalizeBatchTxData parses the finalizeBatch or importGenesisBatch transaction's input data to get BatchHeaderBytes -// Both finalizeBatch(bytes calldata _batchHeader) and importGenesisBatch(bytes calldata _batchHeader) receive one parameter: batchHeader bytes -// Both methods emit FinalizeBatch event, so we need to support parsing both -func parseFinalizeBatchTxData(txData []byte) (BatchHeaderBytes, error) { - // Get rollup ABI - rollupAbi, err := bindings.RollupMetaData.GetAbi() +func (bc *BatchCache) reconstructCommittedBatchHeader( + index uint64, + expectedHash common.Hash, + tx *ethtypes.Transaction, +) (BatchHeaderBytes, error) { + if tx == nil { + return nil, errors.New("nil canonical commit transaction") + } + genesis, matched, err := decodeImportGenesisHeader(tx.Data()) if err != nil { return nil, err } - - // Check if the first 4 bytes of transaction data match the method ID - if len(txData) < 4 { - return nil, errors.New("transaction data too short") + if matched { + if err := verifyHeaderIdentity(genesis, index, expectedHash); err != nil { + return nil, err + } + if err := bc.verifyFinalizedMessageCursor(genesis); err != nil { + return nil, err + } + return genesis, nil } - methodID := txData[:4] + abis, err := DefaultRollupABIs() + if err != nil { + return nil, err + } + decoded, err := decodeBatchCall(tx.Data(), abis) + if err != nil { + return nil, err + } + if decoded.input.Version > BatchHeaderVersion2 { + return nil, fmt.Errorf("canonical commit has unsupported batch version %d", decoded.input.Version) + } + if len(decoded.explicitHeader) > 0 { + if err := verifyHeaderIdentity(decoded.explicitHeader, index, expectedHash); err != nil { + return nil, fmt.Errorf("invalid explicit header in %s.%s: %w", decoded.era, decoded.method, err) + } + if err := bc.verifyFinalizedMessageCursor(decoded.explicitHeader); err != nil { + return nil, err + } + return decoded.explicitHeader, nil + } - // Try to get finalizeBatch method - finalizeBatchMethod, ok := rollupAbi.Methods["finalizeBatch"] - if !ok { - return nil, errors.New("finalizeBatch method not found in ABI") + parent := BatchHeaderBytes(decoded.input.ParentBatchHeader) + parentIndex, err := parent.BatchIndex() + if err != nil { + return nil, fmt.Errorf("decode parent batch header index: %w", err) + } + if parentIndex == ^uint64(0) || parentIndex+1 != index { + return nil, fmt.Errorf("canonical commit parent index mismatch: parent=%d current=%d", parentIndex, index) + } + parentHash, err := parent.Hash() + if err != nil { + return nil, fmt.Errorf("hash parent batch header: %w", err) + } + parentCursor, err := parent.TotalL1MessagePopped() + if err != nil { + return nil, fmt.Errorf("decode parent L1 message cursor: %w", err) } - var method abi.Method - var methodName string + queue, err := bc.l1MessageQueue() + if err != nil { + return nil, err + } + var ( + dataHash common.Hash + l1MessageCount uint64 + ) + switch decoded.era { + case "pre-submitter", "current": + l1MessageCount = uint64(decoded.input.NumL1Messages) + if l1MessageCount > ^uint64(0)-parentCursor { + return nil, fmt.Errorf("L1 message cursor overflow: parent=%d batch=%d", parentCursor, l1MessageCount) + } + data := make([]byte, 10, 10+32*int(l1MessageCount)) + binary.BigEndian.PutUint64(data[:8], decoded.input.LastBlockNumber) + binary.BigEndian.PutUint16(data[8:10], decoded.input.NumL1Messages) + for i := uint64(0); i < l1MessageCount; i++ { + messageHash, err := queue.GetCrossDomainMessage( + bc.snapshotCallOpts(), + new(big.Int).SetUint64(parentCursor+i), + ) + if err != nil { + return nil, fmt.Errorf("read L1 message %d for canonical batch %d: %w", parentCursor+i, index, err) + } + data = append(data, messageHash[:]...) + } + dataHash = crypto.Keccak256Hash(data) + case "before-move-block-context", "legacy": + data, count, err := bc.reconstructBlockContextData(decoded, parentCursor, queue) + if err != nil { + return nil, err + } + l1MessageCount = count + dataHash = crypto.Keccak256Hash(data) + default: + return nil, fmt.Errorf("unsupported canonical commit ABI era %q", decoded.era) + } + if l1MessageCount > ^uint64(0)-parentCursor { + return nil, fmt.Errorf("L1 message cursor overflow: parent=%d batch=%d", parentCursor, l1MessageCount) + } + totalCursor := parentCursor + l1MessageCount - // Check if method ID matches finalizeBatch - if bytes.Equal(methodID, finalizeBatchMethod.ID) { - method = finalizeBatchMethod - methodName = "finalizeBatch" + blobHashRaw, err := bc.rollupContract.BatchBlobVersionedHashes( + bc.snapshotCallOpts(), + new(big.Int).SetUint64(index), + ) + if err != nil { + return nil, fmt.Errorf("read blob hash for canonical batch %d: %w", index, err) + } + blobCommitHash, err := canonicalBlobCommitHash(tx, decoded, common.Hash(blobHashRaw)) + if err != nil { + return nil, err + } + base := BatchHeaderV0{ + BatchIndex: index, + L1MessagePopped: l1MessageCount, + TotalL1MessagePopped: totalCursor, + DataHash: dataHash, + BlobVersionedHash: blobCommitHash, + PrevStateRoot: common.Hash(decoded.input.PrevStateRoot), + PostStateRoot: common.Hash(decoded.input.PostStateRoot), + WithdrawalRoot: common.Hash(decoded.input.WithdrawalRoot), + SequencerSetVerifyHash: decoded.sequencerSetHash, + ParentBatchHash: parentHash, + } + var header BatchHeaderBytes + if decoded.input.Version >= BatchHeaderVersion1 { + header = BatchHeaderV1{ + BatchHeaderV0: base, + LastBlockNumber: decoded.input.LastBlockNumber, + }.Bytes() + if decoded.input.Version == BatchHeaderVersion2 { + header[0] = BatchHeaderVersion2 + } } else { - // Try importGenesisBatch method - importGenesisBatchMethod, ok := rollupAbi.Methods["importGenesisBatch"] - if !ok { - return nil, errors.New("importGenesisBatch method not found in ABI") - } - if bytes.Equal(methodID, importGenesisBatchMethod.ID) { - method = importGenesisBatchMethod - methodName = "importGenesisBatch" - } else { - return nil, fmt.Errorf("transaction is not a finalizeBatch or importGenesisBatch call, methodID: %x", methodID) + header = base.Bytes() + if decoded.era == "legacy" { + header = append(header, decoded.skippedBitmap...) } } + if err := verifyHeaderIdentity(header, index, expectedHash); err != nil { + return nil, fmt.Errorf("reconstructed %s.%s header: %w", decoded.era, decoded.method, err) + } + if err := bc.verifyFinalizedMessageCursor(header); err != nil { + return nil, err + } + return header, nil +} - // Parse parameters (only one parameter: batchHeader bytes) - args, err := method.Inputs.Unpack(txData[4:]) - if err != nil { - return nil, fmt.Errorf("failed to unpack %s transaction parameters: %w", methodName, err) +func canonicalBlobCommitHash( + tx *ethtypes.Transaction, + decoded *decodedBatchCall, + stored common.Hash, +) (common.Hash, error) { + hashes := tx.BlobHashes() + if len(hashes) == 0 { + if decoded.era == "current" && decoded.method == "commitBatch" { + return common.Hash{}, errors.New("current canonical commitBatch has no fresh blob hash") + } + if stored != (common.Hash{}) { + return stored, nil + } + if decoded.method == "commitState" || decoded.input.Version >= BatchHeaderVersion2 { + return common.Hash{}, fmt.Errorf("%s.%s has no recoverable stored blob hash", decoded.era, decoded.method) + } + // Frozen V0/V1 commitBatch transactions mined before blobs were + // available used the protocol's non-zero empty versioned hash. + return blob.EmptyVersionedHash, nil } - if len(args) == 0 { - return nil, fmt.Errorf("no arguments found in %s transaction", methodName) + var fromTransaction common.Hash + if decoded.input.Version >= BatchHeaderVersion2 { + fromTransaction = aggregateBlobHashes(hashes) + } else { + fromTransaction = hashes[0] + } + if stored != (common.Hash{}) && stored != fromTransaction { + return common.Hash{}, fmt.Errorf("canonical batch blob hash mismatch: stored=%s transaction=%s", stored, fromTransaction) } + return fromTransaction, nil +} - // The first parameter is batchHeader bytes - batchHeaderBytes, ok := args[0].([]byte) +func decodeImportGenesisHeader(data []byte) (BatchHeaderBytes, bool, error) { + rollupABI, err := bindings.RollupMetaData.GetAbi() + if err != nil { + return nil, false, err + } + method, ok := rollupABI.Methods["importGenesisBatch"] + if !ok || len(data) < 4 || !bytes.Equal(data[:4], method.ID) { + return nil, false, nil + } + args, err := method.Inputs.Unpack(data[4:]) + if err != nil { + return nil, true, fmt.Errorf("decode importGenesisBatch: %w", err) + } + if len(args) != 1 { + return nil, true, fmt.Errorf("decode importGenesisBatch: expected one argument, got %d", len(args)) + } + header, ok := args[0].([]byte) if !ok { - return nil, fmt.Errorf("failed to cast batchHeader to []byte in %s transaction", methodName) + return nil, true, errors.New("decode importGenesisBatch: invalid header argument") } - - return BatchHeaderBytes(batchHeaderBytes), nil + return BatchHeaderBytes(bytes.Clone(header)), true, nil } -// batchDataInputStruct represents the parsed batch data input structure from ABI -type batchDataInputStruct struct { - Version uint8 `json:"version"` - ParentBatchHeader []uint8 `json:"parentBatchHeader"` - LastBlockNumber uint64 `json:"lastBlockNumber"` - NumL1Messages uint16 `json:"numL1Messages"` - PrevStateRoot [32]uint8 `json:"prevStateRoot"` - PostStateRoot [32]uint8 `json:"postStateRoot"` - WithdrawalRoot [32]uint8 `json:"withdrawalRoot"` +func verifyHeaderIdentity(header BatchHeaderBytes, index uint64, expectedHash common.Hash) error { + gotIndex, err := header.BatchIndex() + if err != nil { + return fmt.Errorf("decode batch header index: %w", err) + } + if gotIndex != index { + return fmt.Errorf("batch header index mismatch: event=%d header=%d", index, gotIndex) + } + gotHash, err := header.Hash() + if err != nil { + return fmt.Errorf("hash batch header: %w", err) + } + if gotHash != expectedHash { + return fmt.Errorf("batch header hash mismatch: getter=%s reconstructed=%s", expectedHash, gotHash) + } + return nil } -// batchSignatureInputStruct represents the parsed batch signature input structure from ABI -type batchSignatureInputStruct struct { - SignedSequencersBitmap *big.Int `json:"signedSequencersBitmap"` - SequencerSets []uint8 `json:"sequencerSets"` - Signature []uint8 `json:"signature"` +func (bc *BatchCache) l1MessageQueue() (*bindings.L1MessageQueueWithGasPriceOracleCaller, error) { + address, err := bc.rollupContract.MessageQueue(bc.snapshotCallOpts()) + if err != nil { + return nil, fmt.Errorf("read Rollup messageQueue at snapshot: %w", err) + } + if address == (common.Address{}) { + return nil, errors.New("Rollup messageQueue is zero at snapshot") + } + queue, err := bindings.NewL1MessageQueueWithGasPriceOracleCaller(address, bc.l1Client) + if err != nil { + return nil, fmt.Errorf("bind L1 message queue %s: %w", address, err) + } + return queue, nil } -// convertBatchDataInput converts the parsed struct to bindings.IRollupBatchDataInput -func convertBatchDataInput(s batchDataInputStruct) *bindings.IRollupBatchDataInput { - // Convert []uint8 to []byte - parentBatchHeader := make([]byte, len(s.ParentBatchHeader)) - copy(parentBatchHeader, s.ParentBatchHeader) +func (bc *BatchCache) verifyFinalizedMessageCursor(header BatchHeaderBytes) error { + total, err := header.TotalL1MessagePopped() + if err != nil { + return fmt.Errorf("decode finalized L1 message cursor: %w", err) + } + queue, err := bc.l1MessageQueue() + if err != nil { + return err + } + pending, err := queue.PendingQueueIndex(bc.snapshotCallOpts()) + if err != nil { + return fmt.Errorf("read finalized L1 message queue cursor: %w", err) + } + if pending == nil || !pending.IsUint64() || pending.Uint64() != total { + return fmt.Errorf("finalized L1 message cursor mismatch: header=%d queue=%v", total, pending) + } + next, err := queue.NextCrossDomainMessageIndex(bc.snapshotCallOpts()) + if err != nil { + return fmt.Errorf("read next L1 message queue index: %w", err) + } + if next == nil || !next.IsUint64() || next.Uint64() < total { + return fmt.Errorf("L1 message queue shorter than finalized cursor: header=%d next=%v", total, next) + } + return nil +} - return &bindings.IRollupBatchDataInput{ - Version: s.Version, - ParentBatchHeader: parentBatchHeader, - LastBlockNumber: s.LastBlockNumber, - NumL1Messages: s.NumL1Messages, - PrevStateRoot: s.PrevStateRoot, - PostStateRoot: s.PostStateRoot, - WithdrawalRoot: s.WithdrawalRoot, +func (bc *BatchCache) reconstructBlockContextData( + decoded *decodedBatchCall, + parentCursor uint64, + queue *bindings.L1MessageQueueWithGasPriceOracleCaller, +) ([]byte, uint64, error) { + contexts := decoded.blockContexts + if len(contexts) < 2 { + return nil, 0, fmt.Errorf("%s block contexts are shorter than count prefix", decoded.era) + } + blockCount := int(binary.BigEndian.Uint16(contexts[:2])) + if blockCount == 0 || len(contexts) != 2+blockCount*60 { + return nil, 0, fmt.Errorf("%s block context length mismatch: blocks=%d bytes=%d", decoded.era, blockCount, len(contexts)) + } + data := make([]byte, 0, blockCount*58) + var messageCount uint64 + for i := 0; i < blockCount; i++ { + contextBytes := contexts[2+i*60 : 2+(i+1)*60] + data = append(data, contextBytes[:58]...) + messageCount += uint64(binary.BigEndian.Uint16(contextBytes[58:60])) + } + if decoded.era == "legacy" { + expectedBitmapBytes := int((messageCount + 255) / 256 * 32) + if len(decoded.skippedBitmap) != expectedBitmapBytes { + return nil, 0, fmt.Errorf("legacy skipped bitmap length mismatch: messages=%d expected=%d actual=%d", messageCount, expectedBitmapBytes, len(decoded.skippedBitmap)) + } + } + if messageCount > ^uint64(0)-parentCursor { + return nil, 0, fmt.Errorf("historical L1 message cursor overflow: parent=%d batch=%d", parentCursor, messageCount) } + for i := uint64(0); i < messageCount; i++ { + if decoded.era == "legacy" && legacyMessageSkipped(decoded.skippedBitmap, i) { + continue + } + messageHash, err := queue.GetCrossDomainMessage( + bc.snapshotCallOpts(), + new(big.Int).SetUint64(parentCursor+i), + ) + if err != nil { + return nil, 0, fmt.Errorf("read historical L1 message %d: %w", parentCursor+i, err) + } + data = append(data, messageHash[:]...) + } + return data, messageCount, nil } -// convertBatchSignatureInput converts the parsed struct to bindings.IRollupBatchSignatureInput -func convertBatchSignatureInput(s batchSignatureInputStruct) *bindings.IRollupBatchSignatureInput { - // Convert []uint8 to []byte - sequencerSets := make([]byte, len(s.SequencerSets)) - copy(sequencerSets, s.SequencerSets) - signature := make([]byte, len(s.Signature)) - copy(signature, s.Signature) +func legacyMessageSkipped(bitmap []byte, index uint64) bool { + wordStart := int(index/256) * 32 + bitInWord := index % 256 + byteIndex := wordStart + 31 - int(bitInWord/8) + return byteIndex >= 0 && byteIndex < len(bitmap) && bitmap[byteIndex]&(1< 0 { - parentBatchHeader, err := getLastFinalizeBatchHeaderByIndex(batchIndex - 1) - if err == nil { - parentBytes := parentBatchHeader.Bytes() - if !bytes.Equal(parentBytes, batchDataInput.ParentBatchHeader) { - t.Errorf("❌ ParentBatchHeader mismatch: assembled=%x, commitBatch=%x", parentBytes[:min(32, len(parentBytes))], batchDataInput.ParentBatchHeader[:min(32, len(batchDataInput.ParentBatchHeader))]) - } else { - t.Logf("✓ ParentBatchHeader: match") - } - } - } - - // Compare LastBlockNumber - lastBlock, err := assembledBatchHeader.LastBlockNumber() - if err == nil { - if lastBlock != batchDataInput.LastBlockNumber { - t.Errorf("❌ LastBlockNumber mismatch: assembled=%d, commitBatch=%d", lastBlock, batchDataInput.LastBlockNumber) - } else { - t.Logf("✓ LastBlockNumber: %d (match)", lastBlock) - } - } - - // Compare NumL1Messages - l1MsgPopped, err := assembledBatchHeader.L1MessagePopped() - require.NoError(t, err) - if l1MsgPopped != uint64(batchDataInput.NumL1Messages) { - t.Errorf("❌ NumL1Messages mismatch: assembled=%d, commitBatch=%d", l1MsgPopped, batchDataInput.NumL1Messages) - } else { - t.Logf("✓ NumL1Messages: %d (match)", l1MsgPopped) - } - - // Compare PrevStateRoot - prevStateRoot, err := assembledBatchHeader.PrevStateRoot() - require.NoError(t, err) - prevStateRootFromCommit := common.BytesToHash(batchDataInput.PrevStateRoot[:]) - if prevStateRoot != prevStateRootFromCommit { - t.Errorf("❌ PrevStateRoot mismatch: assembled=%x, commitBatch=%x", prevStateRoot, prevStateRootFromCommit) - } else { - t.Logf("✓ PrevStateRoot: %x (match)", prevStateRoot) - } - - // Compare PostStateRoot - postStateRoot, err := assembledBatchHeader.PostStateRoot() - require.NoError(t, err) - postStateRootFromCommit := common.BytesToHash(batchDataInput.PostStateRoot[:]) - if postStateRoot != postStateRootFromCommit { - t.Errorf("❌ PostStateRoot mismatch: assembled=%x, commitBatch=%x", postStateRoot, postStateRootFromCommit) - } else { - t.Logf("✓ PostStateRoot: %x (match)", postStateRoot) - } - - // Compare WithdrawalRoot - withdrawRoot, err := assembledBatchHeader.WithdrawalRoot() - require.NoError(t, err) - withdrawRootFromCommit := common.BytesToHash(batchDataInput.WithdrawalRoot[:]) - if withdrawRoot != withdrawRootFromCommit { - t.Errorf("❌ WithdrawalRoot mismatch: assembled=%x, commitBatch=%x", withdrawRoot, withdrawRootFromCommit) - } else { - t.Logf("✓ WithdrawalRoot: %x (match)", withdrawRoot) - } - - // Compare SequencerSetVerifyHash - sequencerSetsHash := crypto.Keccak256Hash(batchSignatureInput.SequencerSets) - seqHash, err := assembledBatchHeader.SequencerSetVerifyHash() - require.NoError(t, err) - if seqHash != sequencerSetsHash { - t.Errorf("❌ SequencerSetVerifyHash mismatch: assembled=%x, from SequencerSets=%x", seqHash, sequencerSetsHash) - } else { - t.Logf("✓ SequencerSetVerifyHash: %x (match)", seqHash) - } - - if seqHash != sequencerSetVerifyHash { - t.Errorf("❌ SequencerSetVerifyHash mismatch with provided hash: assembled=%x, provided=%x", seqHash, sequencerSetVerifyHash) - } else { - t.Logf("✓ SequencerSetVerifyHash matches provided hash: %x", sequencerSetVerifyHash) - } -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -// getLastFinalizeBatchHeaderByIndex gets the batch header with the specified index from the rollup contract's FinalizeBatch event -// The finalizeBatch function only receives one parameter: batchHeader bytes, so it can be parsed directly from the transaction -// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found -func getLastFinalizeBatchHeaderByIndex(index uint64) (*BatchHeaderBytes, error) { - // Get the current latest block height - latestBlock, err := l1Client.BlockNumber(context.Background()) - if err != nil { - return nil, fmt.Errorf("failed to get latest block number: %w", err) - } - - const blockRange = uint64(10000) // Query 10000 blocks each time - var endBlock uint64 = latestBlock - var startBlock uint64 - - // Start from the latest height, query backwards 10000 blocks each time until data is found - for endBlock > 0 { - // Calculate the start block for this query - if endBlock >= blockRange { - startBlock = endBlock - blockRange + 1 - } else { - startBlock = 0 - } - - // Set query options - filterOpts := &bind.FilterOpts{ - Start: startBlock, - End: &endBlock, - } - - // Query the FinalizeBatch event with the corresponding index from the rollup contract - finalizeEventIter, err := rollupContract.FilterFinalizeBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) - if err != nil { - // If query fails, continue querying backwards - if endBlock < blockRange { - break // Already queried to block 0, exit loop - } - endBlock = startBlock - 1 - continue - } - - // Iterate through query results - for finalizeEventIter.Next() { - event := finalizeEventIter.Event - // Get transaction hash from event - txHash := event.Raw.TxHash - - // Get transaction details - tx, _, err := l1Client.TransactionByHash(context.Background(), txHash) - if err != nil { - continue // If getting transaction fails, try next event - } - - // Parse finalizeBatch transaction data to get batchHeader - batchHeader, err := parseFinalizeBatchTxData(tx.Data()) - if err != nil { - continue // If parsing fails, try next event - } - - // Verify if batch index matches - batchIndex, err := batchHeader.BatchIndex() - if err != nil { - continue - } - if batchIndex == index { - finalizeEventIter.Close() - return &batchHeader, nil - } - } - finalizeEventIter.Close() - - // Continue querying backwards - if endBlock < blockRange { - break // Already queried to block 0, exit loop - } - endBlock = startBlock - 1 - } - - return nil, ErrBatchNotFound -} - -func getInfosFromContract() (*big.Int, *big.Int) { - latestCommitBatchIndex, _ := rollupContract.LastCommittedBatchIndex(nil) - lastFinalizedBatchIndex, _ := rollupContract.LastFinalizedBatchIndex(nil) - return latestCommitBatchIndex, lastFinalizedBatchIndex -} - -func getFirstUnFinalizeBatchBlockNumRange(lastFinalizedBatchIndex *big.Int) (*big.Int, *big.Int, error) { - fis, err := rollupContract.BatchDataStore(nil, lastFinalizedBatchIndex) - if err != nil { - return nil, nil, err - } - ufis, err := rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(lastFinalizedBatchIndex.Uint64()+1)) - if err != nil { - return nil, nil, err - } - - return fis.BlockNumber, ufis.BlockNumber, nil -} - -// getCommitBatchDataByIndex gets batchDataInput and batchSignatureInput with the specified index from the rollup contract's CommitBatch event -// Reference the implementation of getLastFinalizeBatchHeaderByIndex -// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found -func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, *bindings.IRollupBatchSignatureInput, error) { - // Get the current latest block height - latestBlock, err := l1Client.BlockNumber(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("failed to get latest block number: %w", err) - } - - const blockRange = uint64(10000) // Query 10000 blocks each time - var endBlock uint64 = latestBlock - var startBlock uint64 - - // Start from the latest height, query backwards 10000 blocks each time until data is found - for endBlock > 0 { - // Calculate the start block for this query - if endBlock >= blockRange { - startBlock = endBlock - blockRange + 1 - } else { - startBlock = 0 - } - - // Set query options - filterOpts := &bind.FilterOpts{ - Start: startBlock, - End: &endBlock, - } - - // Query the CommitBatch event with the corresponding index from the rollup contract - commitEventIter, err := rollupContract.FilterCommitBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) - if err != nil { - // If query fails, continue querying backwards - if endBlock < blockRange { - break // Already queried to block 0, exit loop - } - endBlock = startBlock - 1 - continue - } - - // Iterate through query results - for commitEventIter.Next() { - event := commitEventIter.Event - // Get transaction hash from event - txHash := event.Raw.TxHash - - // Get transaction details - tx, _, err := l1Client.TransactionByHash(context.Background(), txHash) - if err != nil { - return nil, nil, fmt.Errorf("failed to get transaction by hash: %w", err) - } - - // Parse commitBatch transaction data to get batchDataInput and batchSignatureInput - batchDataInput, batchSignatureInput, err := parseCommitBatchTxData(tx.Data()) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse commit batch data: %w", err) - } - - // Verify if batch index matches (by checking batchIndex in parentBatchHeader) - if len(batchDataInput.ParentBatchHeader) > 0 { - parentHeader := BatchHeaderBytes(batchDataInput.ParentBatchHeader) - parentBatchIndex, err := parentHeader.BatchIndex() - if err == nil && parentBatchIndex+1 == index { - commitEventIter.Close() - return batchDataInput, batchSignatureInput, nil - } - } - } - commitEventIter.Close() - - // Continue querying backwards - if endBlock < blockRange { - break // Already queried to block 0, exit loop - } - endBlock = startBlock - 1 - } - - return nil, nil, ErrBatchNotFound -} - -// assembleBatchHeaderFromL2Blocks fetches blocks from L2 client in the specified range and assembles batchHeader -// Parameters: -// - bc: BatchCache instance (parentBatchHeader and prevStateRoot already initialized) -// - startBlockNum: starting block number -// - endBlockNum: ending block number -// - sequencerSetVerifyHash: sequencer set verification hash -// - l2Client: L2 client -// -// Returns: -// - batchHeader: assembled batchHeader -// - error: returns error if assembly fails -func assembleBatchHeaderFromL2Blocks( - bc *BatchCache, - startBlockNum, endBlockNum uint64, - sequencerBytes []byte, - l2Client *ethclient.Client, - l2Gov L2GovCaller, -) (*BatchHeaderBytes, error) { - ctx := context.Background() - - // Fetch blocks from L2 client in the specified range and accumulate to batch - for blockNum := startBlockNum; blockNum <= endBlockNum; blockNum++ { - root, err := l2Gov.GetTreeRoot(&bind.CallOpts{ - Context: ctx, - BlockNumber: new(big.Int).SetUint64(blockNum), - }) - if err != nil { - return nil, fmt.Errorf("failed to get withdraw root at block %d: %w", blockNum, err) - } - // Check capacity and store to current - exceeded, err := bc.CalculateCapWithProposalBlock(blockNum, root) - if err != nil { - return nil, fmt.Errorf("failed to calculate cap with block %d: %w", blockNum, err) - } - - // Pack current block (confirm and append to batch) - if err = bc.PackCurrentBlock(blockNum); err != nil { - return nil, fmt.Errorf("failed to pack block %d: %w", blockNum, err) - } - - // If capacity exceeds limit, can stop early (optional) - _ = exceeded // Checked but not used in this test - } - - // Get the last block's timestamp for packing - lastBlock, err := l2Client.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) - if err != nil { - return nil, fmt.Errorf("failed to get last block %d: %w", endBlockNum, err) - } - blockTimestamp := lastBlock.Time() - - // Seal batch and generate batchHeader - batchIndex, batchHeaderBytes, _, err := bc.SealBatch(sequencerBytes, blockTimestamp, nil) - if err != nil { - return nil, fmt.Errorf("failed to seal batch: %w", err) - } - - // Get the sealed batch header - _, found := bc.GetSealedBatch(batchIndex) - if !found { - return nil, fmt.Errorf("sealed batch not found for index %d", batchIndex) - } - - return &batchHeaderBytes, nil + requireBatchIntegration(t) + cache := NewBatchCache( + nil, + nil, + 2, + testBatchConfig, + l1Client, + &SingleL2Client{C: l2Client}, + rollupContract, + l2Gov, + openTestKV(t), + ) + require.NoError(t, cache.InitAndSyncFromRollup()) + require.True(t, cache.isInitialized()) } diff --git a/common/batch/batch_storage_test.go b/common/batch/batch_storage_test.go index 9ceee7da2..fceea3dcc 100644 --- a/common/batch/batch_storage_test.go +++ b/common/batch/batch_storage_test.go @@ -233,7 +233,7 @@ func TestSealBatchPropagatesStoreErrorAndKeepsState(t *testing.T) { originalBatchData := bc.batchData originalParent := bc.parentBatchHeader - _, _, _, err := bc.SealBatch([]byte{1}, 1, nil) + _, _, _, err := bc.SealBatch(1, nil) require.ErrorIs(t, err, errWriteBatchUnavailable) require.Empty(t, bc.sealedBatches) require.Empty(t, bc.sealedBatchHeaders) diff --git a/common/batch/canonical_bootstrap_test.go b/common/batch/canonical_bootstrap_test.go new file mode 100644 index 000000000..fd9a58a02 --- /dev/null +++ b/common/batch/canonical_bootstrap_test.go @@ -0,0 +1,386 @@ +package batch + +import ( + "bytes" + "context" + "encoding/binary" + "errors" + "math/big" + "testing" + + "morph-l2/bindings/bindings" + + "github.com/holiman/uint256" + "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" + "github.com/morph-l2/go-ethereum/eth" + "github.com/morph-l2/go-ethereum/rpc" + "github.com/stretchr/testify/require" +) + +func TestSelectCanonicalCommitUsesRecommitAfterLastRevert(t *testing.T) { + hash := common.HexToHash("0x1234") + commits := []canonicalCommitEvent{ + {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 10, TxIndex: 1, Index: 2}}, + {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 12, TxIndex: 0, Index: 0}}, + } + reverts := []canonicalRevertEvent{ + {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 11, TxIndex: 3, Index: 4}}, + } + + selected, err := selectCanonicalCommit(9, hash, commits, reverts) + require.NoError(t, err) + require.Equal(t, uint64(12), selected.raw.BlockNumber) + + // Ordering includes transaction and log index, not just block number. + commits = append(commits, canonicalCommitEvent{ + batchIndex: 9, + batchHash: hash, + raw: ethtypes.Log{BlockNumber: 12, TxIndex: 0, Index: 3}, + }) + selected, err = selectCanonicalCommit(9, hash, commits, reverts) + require.NoError(t, err) + require.Equal(t, uint(3), selected.raw.Index) +} + +func TestSelectCanonicalCommitRejectsEmptyCheckpoint(t *testing.T) { + _, err := selectCanonicalCommit(7, common.Hash{}, nil, nil) + require.ErrorContains(t, err, "no canonical committed hash") +} + +type queueBackend struct { + messages map[uint64]common.Hash + pending uint64 + next uint64 + callBlocks []uint64 + latest uint64 + headers []*ethtypes.Header + headerReads int + transactions map[common.Hash]*ethtypes.Transaction +} + +func (b *queueBackend) CodeAt(context.Context, common.Address, *big.Int) ([]byte, error) { + return []byte{1}, nil +} + +func (b *queueBackend) CallContract(_ context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + if blockNumber == nil { + return nil, errors.New("queue getter was not pinned to snapshot") + } + b.callBlocks = append(b.callBlocks, blockNumber.Uint64()) + if len(call.Data) < 4 { + return nil, errors.New("short queue calldata") + } + selector := call.Data[:4] + switch { + case bytes.Equal(selector, crypto.Keccak256([]byte("getCrossDomainMessage(uint256)"))[:4]): + if len(call.Data) != 36 { + return nil, errors.New("invalid message getter calldata") + } + index := new(big.Int).SetBytes(call.Data[4:]).Uint64() + hash, ok := b.messages[index] + if !ok { + return nil, errors.New("message index unavailable") + } + return hash.Bytes(), nil + case bytes.Equal(selector, crypto.Keccak256([]byte("pendingQueueIndex()"))[:4]): + return common.LeftPadBytes(new(big.Int).SetUint64(b.pending).Bytes(), 32), nil + case bytes.Equal(selector, crypto.Keccak256([]byte("nextCrossDomainMessageIndex()"))[:4]): + return common.LeftPadBytes(new(big.Int).SetUint64(b.next).Bytes(), 32), nil + default: + return nil, errors.New("unexpected queue getter") + } +} + +func (b *queueBackend) BlockNumber(context.Context) (uint64, error) { return b.latest, nil } + +func (b *queueBackend) HeaderByNumber(context.Context, *big.Int) (*ethtypes.Header, error) { + if len(b.headers) == 0 { + return nil, errors.New("header unavailable") + } + index := b.headerReads + if index >= len(b.headers) { + index = len(b.headers) - 1 + } + b.headerReads++ + return b.headers[index], nil +} + +func (b *queueBackend) TransactionByHash(_ context.Context, hash common.Hash) (*ethtypes.Transaction, bool, error) { + tx, ok := b.transactions[hash] + if !ok { + return nil, false, errors.New("transaction unavailable") + } + return tx, false, nil +} + +type canonicalRollupStub struct { + blobHash common.Hash + queueAddress common.Address + callBlockReads []uint64 +} + +func (r *canonicalRollupStub) record(opts *bind.CallOpts) error { + if opts == nil || opts.BlockNumber == nil { + return errors.New("rollup getter was not pinned to snapshot") + } + r.callBlockReads = append(r.callBlockReads, opts.BlockNumber.Uint64()) + return nil +} + +func (r *canonicalRollupStub) BatchBlobVersionedHashes(opts *bind.CallOpts, _ *big.Int) ([32]byte, error) { + if err := r.record(opts); err != nil { + return [32]byte{}, err + } + return [32]byte(r.blobHash), nil +} + +func (r *canonicalRollupStub) MessageQueue(opts *bind.CallOpts) (common.Address, error) { + if err := r.record(opts); err != nil { + return common.Address{}, err + } + return r.queueAddress, nil +} + +func (*canonicalRollupStub) CommittedBatches(*bind.CallOpts, *big.Int) ([32]byte, error) { + return [32]byte{}, errors.New("not implemented") +} +func (*canonicalRollupStub) LastCommittedBatchIndex(*bind.CallOpts) (*big.Int, error) { + return nil, errors.New("not implemented") +} +func (*canonicalRollupStub) LastFinalizedBatchIndex(*bind.CallOpts) (*big.Int, error) { + return nil, errors.New("not implemented") +} +func (*canonicalRollupStub) BatchDataStore(*bind.CallOpts, *big.Int) (struct { + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address +}, error) { + return struct { + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address + }{}, errors.New("not implemented") +} +func (*canonicalRollupStub) FinalizedStateRoots(*bind.CallOpts, *big.Int) ([32]byte, error) { + return [32]byte{}, errors.New("not implemented") +} +func (*canonicalRollupStub) FilterCommitBatch(*bind.FilterOpts, []*big.Int, [][32]byte) (*bindings.RollupCommitBatchIterator, error) { + return nil, errors.New("not implemented") +} +func (*canonicalRollupStub) FilterRevertBatch(*bind.FilterOpts, []*big.Int, [][32]byte) (*bindings.RollupRevertBatchIterator, error) { + return nil, errors.New("not implemented") +} + +func TestReconstructCurrentCanonicalCommitAtPinnedSnapshot(t *testing.T) { + parent := BatchHeaderV1{ + BatchHeaderV0: BatchHeaderV0{ + BatchIndex: 7, + TotalL1MessagePopped: 3, + PostStateRoot: common.HexToHash("0x70"), + }, + LastBlockNumber: 90, + }.Bytes() + input := bindings.IRollupBatchDataInput{ + Version: BatchHeaderVersion1, + ParentBatchHeader: parent, + LastBlockNumber: 100, + NumL1Messages: 2, + PrevStateRoot: common.HexToHash("0x70"), + PostStateRoot: common.HexToHash("0x80"), + WithdrawalRoot: common.HexToHash("0x90"), + } + abis, err := DefaultRollupABIs() + require.NoError(t, err) + calldata, err := abis.Current.Pack("commitBatch", input) + require.NoError(t, err) + + messages := map[uint64]common.Hash{ + 3: common.HexToHash("0x300"), + 4: common.HexToHash("0x400"), + } + data := make([]byte, 10) + binary.BigEndian.PutUint64(data[:8], input.LastBlockNumber) + binary.BigEndian.PutUint16(data[8:], input.NumL1Messages) + data = append(data, messages[3].Bytes()...) + data = append(data, messages[4].Bytes()...) + parentHash, err := parent.Hash() + require.NoError(t, err) + blobHash := common.HexToHash("0xb10b") + expected := BatchHeaderV1{ + BatchHeaderV0: BatchHeaderV0{ + BatchIndex: 8, + L1MessagePopped: 2, + TotalL1MessagePopped: 5, + DataHash: crypto.Keccak256Hash(data), + BlobVersionedHash: blobHash, + PrevStateRoot: common.Hash(input.PrevStateRoot), + PostStateRoot: common.Hash(input.PostStateRoot), + WithdrawalRoot: common.Hash(input.WithdrawalRoot), + ParentBatchHash: parentHash, + }, + LastBlockNumber: input.LastBlockNumber, + }.Bytes() + expectedHash, err := expected.Hash() + require.NoError(t, err) + + backend := &queueBackend{messages: messages, pending: 5, next: 6} + rollup := &canonicalRollupStub{ + blobHash: blobHash, + queueAddress: common.HexToAddress("0x1234"), + } + cache := &BatchCache{ + ctx: context.Background(), + l1Client: backend, + rollupContract: rollup, + l1Snapshot: &confirmedL1Snapshot{number: 99, hash: common.HexToHash("0x99")}, + sealedBatches: make(map[uint64]*eth.RPCRollupBatch), + sealedBatchHeaders: make(map[uint64]*BatchHeaderBytes), + } + tx := ethtypes.NewTx(ðtypes.BlobTx{ + ChainID: uint256.NewInt(1), + GasTipCap: uint256.NewInt(1), + GasFeeCap: uint256.NewInt(1), + Value: uint256.NewInt(0), + Data: calldata, + BlobFeeCap: uint256.NewInt(1), + BlobHashes: []common.Hash{blobHash}, + }) + + got, err := cache.reconstructCommittedBatchHeader(8, expectedHash, tx) + require.NoError(t, err) + require.Equal(t, expected, got) + require.NotEmpty(t, rollup.callBlockReads) + for _, number := range rollup.callBlockReads { + require.Equal(t, uint64(99), number) + } + for _, number := range backend.callBlocks { + require.Equal(t, uint64(99), number) + } + + backend.pending = 4 + _, err = cache.reconstructCommittedBatchHeader(8, expectedHash, tx) + require.ErrorContains(t, err, "cursor mismatch") +} + +func TestConfirmedL1SnapshotHashChangeFailsClosed(t *testing.T) { + number := uint64(14) + backend := &queueBackend{ + latest: 20, + headers: []*ethtypes.Header{ + {Number: new(big.Int).SetUint64(number), Extra: []byte("before")}, + {Number: new(big.Int).SetUint64(number), Extra: []byte("after")}, + }, + } + cache := &BatchCache{ctx: context.Background(), l1Client: backend} + err := cache.withConfirmedL1Snapshot(func() error { + require.Equal(t, number, cache.snapshotCallOpts().BlockNumber.Uint64()) + return nil + }) + require.ErrorContains(t, err, "snapshot changed") + require.Nil(t, cache.l1Snapshot) +} + +type scriptedL2 struct { + safe *ethtypes.Block + numbered map[uint64][]*ethtypes.Block + reads map[uint64]int +} + +func (c *scriptedL2) BlockNumber(context.Context) (uint64, error) { return c.safe.NumberU64(), nil } +func (c *scriptedL2) Len() int { return 1 } +func (c *scriptedL2) BlockByNumber(_ context.Context, number *big.Int) (*ethtypes.Block, error) { + if number.Int64() == int64(rpc.SafeBlockNumber) { + return c.safe, nil + } + n := number.Uint64() + values := c.numbered[n] + if len(values) == 0 { + return nil, nil + } + read := c.reads[n] + if read >= len(values) { + read = len(values) - 1 + } + c.reads[n]++ + return values[read], nil +} + +func l2Block(number uint64, marker string) *ethtypes.Block { + return ethtypes.NewBlockWithHeader(ðtypes.Header{ + Number: new(big.Int).SetUint64(number), + Extra: []byte(marker), + }) +} + +func initializedSafeHeadCache(last uint64, l2 L2MultiClient) *BatchCache { + parent := BatchHeaderV1{ + BatchHeaderV0: BatchHeaderV0{BatchIndex: 3}, + LastBlockNumber: last, + }.Bytes() + return &BatchCache{ + ctx: context.Background(), + initDone: true, + parentBatchHeader: &parent, + lastPackedBlockHeight: last, + currentBlockNumber: last, + batchData: NewBatchData(), + batchConfig: BatchConfig{BlockInterval: 100}, + l2Clients: l2, + } +} + +func TestAssembleCurrentBatchRejectsChangedSafeHeadHash(t *testing.T) { + l2 := &scriptedL2{ + safe: l2Block(10, "safe-before"), + numbered: map[uint64][]*ethtypes.Block{10: {l2Block(10, "safe-after")}}, + reads: make(map[uint64]int), + } + cache := initializedSafeHeadCache(10, l2) + err := cache.AssembleCurrentBatchHeader() + require.ErrorContains(t, err, "safe head changed") +} + +func TestAssembleCurrentBatchRejectsL2Gap(t *testing.T) { + l2 := &scriptedL2{ + safe: l2Block(12, "safe"), + numbered: map[uint64][]*ethtypes.Block{ + 10: {l2Block(10, "parent")}, + 11: {l2Block(12, "wrong-height")}, + }, + reads: make(map[uint64]int), + } + cache := initializedSafeHeadCache(10, l2) + err := cache.AssembleCurrentBatchHeader() + require.ErrorContains(t, err, "L2 gap") +} + +func TestResetCanonicalBootstrapLeavesNoCheckpoint(t *testing.T) { + storage := NewBatchStorage(openTestKV(t)) + storeTestChain(t, storage, []uint64{1, 2}) + header := makeTestHeader(2) + cache := &BatchCache{ + initDone: true, + batchStorage: storage, + sealedBatches: map[uint64]*eth.RPCRollupBatch{2: {}}, + sealedBatchHeaders: map[uint64]*BatchHeaderBytes{2: &header}, + parentBatchHeader: &header, + batchData: NewBatchData(), + currentBlockHash: common.HexToHash("0x1234"), + } + + require.NoError(t, cache.ResetCanonicalBootstrap()) + _, err := storage.loadBatchIndices() + require.True(t, isKVNotFound(err), "checkpoint must be absent after rollback: %v", err) + require.False(t, cache.initDone) + require.Empty(t, cache.sealedBatches) + require.Empty(t, cache.sealedBatchHeaders) + require.Nil(t, cache.parentBatchHeader) + require.Nil(t, cache.batchData) + require.Zero(t, cache.currentBlockHash) +} diff --git a/common/batch/commit_test.go b/common/batch/commit_test.go index c704b885f..da2b84c07 100644 --- a/common/batch/commit_test.go +++ b/common/batch/commit_test.go @@ -13,7 +13,6 @@ import ( "morph-l2/common/blob" "github.com/holiman/uint256" - "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/consensus/misc/eip4844" ethtypes "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto" @@ -34,7 +33,7 @@ func TestRollupWithProof(t *testing.T) { } testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) @@ -53,11 +52,6 @@ func TestRollupWithProof(t *testing.T) { batch, err := cache.Get(latestCommitBatchIndex.Uint64() + 1) require.NoError(t, err) - h := crypto.Keccak256Hash(batch.CurrentSequencerSetBytes) - t.Log("sequencer verify hash:", h.String()) - - signature, err := buildSigInput(batch) - require.NoError(t, err) rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(batch.Version), ParentBatchHeader: batch.ParentBatchHeader, @@ -70,7 +64,7 @@ func TestRollupWithProof(t *testing.T) { tip, gasFeeCap, blobFee, head, err := getGasTipAndCap(l1Client) require.NoError(t, err) - calldata, err := abi.Pack("commitBatch", rollupBatch, *signature) + calldata, err := abi.Pack("commitBatch", rollupBatch) require.NoError(t, err) nonce, err := l1Client.NonceAt(context.Background(), address, nil) require.NoError(t, err) @@ -186,15 +180,6 @@ func getGasTipAndCap(l1client *ethclient.Client) (*big.Int, *big.Int, *big.Int, return tip, gasFeeCap, blobFee, head, nil } -func buildSigInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { - sigData := &bindings.IRollupBatchSignatureInput{ - SignedSequencersBitmap: common.Big0, - SequencerSets: batch.CurrentSequencerSetBytes, - Signature: []byte("0x"), - } - return sigData, nil -} - func sendTx(client *ethclient.Client, txFeeLimit uint64, tx *ethtypes.Transaction) error { if txFeeLimit > 0 { var fee uint64 diff --git a/common/batch/config.go b/common/batch/config.go new file mode 100644 index 000000000..331a01d82 --- /dev/null +++ b/common/batch/config.go @@ -0,0 +1,39 @@ +package batch + +import ( + "encoding/binary" + "errors" + + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/crypto" +) + +const batchConfigHashDomain = "morph.batch-config.v1" + +// BatchConfig contains the two static batching thresholds used by a submitter. +// BlockInterval is measured in L2 blocks and Timeout is measured in seconds. +// Either threshold may be disabled independently, but disabling both would make +// it impossible to guarantee that an in-progress batch is ever sealed. +type BatchConfig struct { + BlockInterval uint64 + Timeout uint64 +} + +// Validate checks the protocol-level zero-value rule for static batching +// configuration. +func (c BatchConfig) Validate() error { + if c.BlockInterval == 0 && c.Timeout == 0 { + return errors.New("batch block interval and timeout cannot both be zero") + } + return nil +} + +// Hash returns a stable, domain-separated hash suitable for comparing the +// effective configuration across preflight, startup and backup instances. +func (c BatchConfig) Hash() common.Hash { + encoded := make([]byte, len(batchConfigHashDomain)+16) + copy(encoded, batchConfigHashDomain) + binary.BigEndian.PutUint64(encoded[len(batchConfigHashDomain):], c.BlockInterval) + binary.BigEndian.PutUint64(encoded[len(batchConfigHashDomain)+8:], c.Timeout) + return crypto.Keccak256Hash(encoded) +} diff --git a/common/batch/config_test.go b/common/batch/config_test.go new file mode 100644 index 000000000..4c98c3db8 --- /dev/null +++ b/common/batch/config_test.go @@ -0,0 +1,36 @@ +package batch + +import ( + "testing" + + "github.com/morph-l2/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestBatchConfigValidate(t *testing.T) { + tests := []struct { + name string + config BatchConfig + wantErr bool + }{ + {name: "interval only", config: BatchConfig{BlockInterval: 10}}, + {name: "timeout only", config: BatchConfig{Timeout: 60}}, + {name: "both", config: BatchConfig{BlockInterval: 10, Timeout: 60}}, + {name: "both zero", config: BatchConfig{}, wantErr: true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.config.Validate() + require.Equal(t, test.wantErr, err != nil) + }) + } +} + +func TestBatchConfigHashIsStableAndFieldSensitive(t *testing.T) { + config := BatchConfig{BlockInterval: 10, Timeout: 60} + require.Equal(t, config.Hash(), config.Hash()) + require.NotEqual(t, common.Hash{}, config.Hash()) + require.NotEqual(t, config.Hash(), (BatchConfig{BlockInterval: 11, Timeout: 60}).Hash()) + require.NotEqual(t, config.Hash(), (BatchConfig{BlockInterval: 10, Timeout: 61}).Hash()) +} diff --git a/common/batch/helpers_test.go b/common/batch/helpers_test.go index f248a2228..081acbe11 100644 --- a/common/batch/helpers_test.go +++ b/common/batch/helpers_test.go @@ -14,6 +14,8 @@ import ( ldbutil "github.com/syndtr/goleveldb/leveldb/util" ) +var testBatchConfig = BatchConfig{BlockInterval: 10_000, Timeout: 10_000_000} + type testLevelDB struct { db *leveldb.DB } @@ -28,6 +30,13 @@ func openTestKV(t *testing.T) SealedBatchKV { return &testLevelDB{db: db} } +func requireBatchIntegration(t *testing.T) { + t.Helper() + if os.Getenv("MORPH_BATCH_INTEGRATION") != "1" { + t.Skip("set MORPH_BATCH_INTEGRATION=1 with local L1/L2 RPCs to run integration test") + } +} + func (d *testLevelDB) GetBytes(key []byte) ([]byte, error) { v, err := d.db.Get(key, nil) if err == ldberrors.ErrNotFound { diff --git a/common/batch/interfaces.go b/common/batch/interfaces.go index 739ef422c..46155df06 100644 --- a/common/batch/interfaces.go +++ b/common/batch/interfaces.go @@ -38,7 +38,9 @@ type SealedBatchKV interface { // L1HeaderClient is the L1 RPC surface required to recover batch headers from events. type L1HeaderClient interface { + bind.ContractCaller BlockNumber(ctx context.Context) (uint64, error) + HeaderByNumber(ctx context.Context, number *big.Int) (*ethtypes.Header, error) TransactionByHash(ctx context.Context, hash common.Hash) (*ethtypes.Transaction, bool, error) } @@ -69,22 +71,23 @@ func (s *SingleL2Client) Len() int { return 1 } // RollupBatchReader is the rollup contract view BatchCache needs (subset of generated Rollup bindings). type RollupBatchReader interface { + BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) - FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) + FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) + MessageQueue(opts *bind.CallOpts) (common.Address, error) + FilterCommitBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupCommitBatchIterator, error) + FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) } -// L2GovCaller reads batch-related Gov / bridge / sequencer data on L2. +// L2GovCaller is the sole L2 contract view needed by batch assembly. type L2GovCaller interface { - BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) - BatchTimeout(opts *bind.CallOpts) (*big.Int, error) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) - GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) } diff --git a/common/batch/l2_gov.go b/common/batch/l2_gov.go index acfe0c0d0..afcab9e07 100644 --- a/common/batch/l2_gov.go +++ b/common/batch/l2_gov.go @@ -1,24 +1,20 @@ package batch import ( - "bytes" "fmt" - "math/big" "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/common/hexutil" - "github.com/morph-l2/go-ethereum/crypto" ) // L2Gov bundles read-only L2 contracts used when assembling rollup batches. +// The name is retained for API compatibility, but batching no longer reads the +// L2 Sequencer or Gov contracts. Only the withdrawal tree root remains an L2 +// contract dependency. type L2Gov struct { - sequencerContract *bindings.SequencerCaller l2MessagePasserContract *bindings.L2ToL1MessagePasserCaller - govContract *bindings.GovCaller } // NewL2Gov builds an L2Gov using any ContractCaller (e.g. *ethclient.Client or a multi-client backend). @@ -26,57 +22,16 @@ func NewL2Gov(backend bind.ContractCaller) (*L2Gov, error) { if backend == nil { return nil, fmt.Errorf("nil contract backend") } - sequencerContract, err := bindings.NewSequencerCaller(predeploys.SequencerAddr, backend) - if err != nil { - return nil, err - } l2MessagePasserContract, err := bindings.NewL2ToL1MessagePasserCaller(predeploys.L2ToL1MessagePasserAddr, backend) if err != nil { return nil, err } - govContract, err := bindings.NewGovCaller(predeploys.GovAddr, backend) - if err != nil { - return nil, err - } return &L2Gov{ - sequencerContract: sequencerContract, l2MessagePasserContract: l2MessagePasserContract, - govContract: govContract, }, nil } -// SequencerSetVerifyHash gets the sequencer set verify hash from the Sequencer contract. -func (c *L2Gov) SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) { - return c.sequencerContract.SequencerSetVerifyHash(opts) -} - // GetTreeRoot gets the tree root from the L2ToL1MessagePasser contract. func (c *L2Gov) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) { return c.l2MessagePasserContract.GetTreeRoot(opts) } - -// BatchBlockInterval gets the batch block interval from the Gov contract. -func (c *L2Gov) BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) { - return c.govContract.BatchBlockInterval(opts) -} - -// BatchTimeout gets the batch timeout from the Gov contract. -func (c *L2Gov) BatchTimeout(opts *bind.CallOpts) (*big.Int, error) { - return c.govContract.BatchTimeout(opts) -} - -// GetSequencerSetBytes returns sequencer set bytes after hash consistency check. -func (c *L2Gov) GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) { - hash, err := c.sequencerContract.SequencerSetVerifyHash(opts) - if err != nil { - return nil, common.Hash{}, err - } - setBytes, err := c.sequencerContract.GetSequencerSetBytes(opts) - if err != nil { - return nil, common.Hash{}, err - } - if bytes.Equal(hash[:], crypto.Keccak256Hash(setBytes).Bytes()) { - return setBytes, hash, nil - } - return nil, common.Hash{}, fmt.Errorf("sequencer set hash verify failed %v: %v", hexutil.Encode(setBytes), common.BytesToHash(hash[:]).String()) -} diff --git a/common/batch/snapshot.go b/common/batch/snapshot.go new file mode 100644 index 000000000..604342e30 --- /dev/null +++ b/common/batch/snapshot.go @@ -0,0 +1,101 @@ +package batch + +import ( + "fmt" + "math/big" + + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" +) + +const canonicalBootstrapConfirmations uint64 = 6 + +type confirmedL1Snapshot struct { + number uint64 + hash common.Hash +} + +// withConfirmedL1Snapshot pins every contract getter and event query performed +// by fn to one confirmed L1 block number, then verifies the block hash again. +// The surrounding initMu serialization guarantees there is at most one active +// bootstrap snapshot per cache. +func (bc *BatchCache) withConfirmedL1Snapshot(fn func() error) error { + if bc.l1Snapshot != nil { + return fn() + } + + latest, err := bc.l1Client.BlockNumber(bc.ctx) + if err != nil { + return fmt.Errorf("read latest L1 block for canonical bootstrap: %w", err) + } + snapshotNumber := uint64(0) + if latest > canonicalBootstrapConfirmations { + snapshotNumber = latest - canonicalBootstrapConfirmations + } + header, err := bc.l1Client.HeaderByNumber(bc.ctx, new(big.Int).SetUint64(snapshotNumber)) + if err != nil { + return fmt.Errorf("read confirmed L1 snapshot %d: %w", snapshotNumber, err) + } + if header == nil { + return fmt.Errorf("read confirmed L1 snapshot %d: nil header", snapshotNumber) + } + if header.Number == nil || header.Number.Uint64() != snapshotNumber { + return fmt.Errorf("confirmed L1 snapshot number mismatch: requested=%d returned=%v", snapshotNumber, header.Number) + } + + bc.l1Snapshot = &confirmedL1Snapshot{number: snapshotNumber, hash: header.Hash()} + opErr := fn() + verifyErr := bc.verifyConfirmedL1Snapshot() + bc.l1Snapshot = nil + if opErr != nil { + if verifyErr != nil { + return fmt.Errorf("canonical bootstrap failed (%v) and snapshot verification failed: %w", opErr, verifyErr) + } + return opErr + } + return verifyErr +} + +func (bc *BatchCache) verifyConfirmedL1Snapshot() error { + if bc.l1Snapshot == nil { + return fmt.Errorf("canonical bootstrap has no confirmed L1 snapshot") + } + header, err := bc.l1Client.HeaderByNumber(bc.ctx, new(big.Int).SetUint64(bc.l1Snapshot.number)) + if err != nil { + return fmt.Errorf("re-read confirmed L1 snapshot %d: %w", bc.l1Snapshot.number, err) + } + if header == nil { + return fmt.Errorf("re-read confirmed L1 snapshot %d: nil header", bc.l1Snapshot.number) + } + if header.Number == nil || header.Number.Uint64() != bc.l1Snapshot.number { + return fmt.Errorf("re-read confirmed L1 snapshot number mismatch: requested=%d returned=%v", bc.l1Snapshot.number, header.Number) + } + if header.Hash() != bc.l1Snapshot.hash { + return fmt.Errorf( + "confirmed L1 snapshot changed during bootstrap: number=%d expected=%s actual=%s", + bc.l1Snapshot.number, + bc.l1Snapshot.hash, + header.Hash(), + ) + } + return nil +} + +func (bc *BatchCache) snapshotCallOpts() *bind.CallOpts { + opts := &bind.CallOpts{Context: bc.ctx} + if bc.l1Snapshot != nil { + opts.BlockNumber = new(big.Int).SetUint64(bc.l1Snapshot.number) + } + return opts +} + +func (bc *BatchCache) snapshotFilterOpts(start, end uint64) (*bind.FilterOpts, error) { + if bc.l1Snapshot == nil { + return nil, fmt.Errorf("canonical event query requires a confirmed L1 snapshot") + } + if end > bc.l1Snapshot.number { + return nil, fmt.Errorf("canonical event query end %d exceeds snapshot %d", end, bc.l1Snapshot.number) + } + endCopy := end + return &bind.FilterOpts{Start: start, End: &endCopy, Context: bc.ctx}, nil +} From c5033de37cebe9c1532e3eda6c9493a1431016ac Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:40:52 +0800 Subject: [PATCH 06/38] feat(submitter): write fresh canonical batches only --- tx-submitter/README.md | 5 +- tx-submitter/constants/methods.go | 7 +- tx-submitter/entry.go | 55 +- tx-submitter/event/indexer.go | 145 ----- tx-submitter/event/storage.go | 109 ---- tx-submitter/event/storage_test.go | 40 -- tx-submitter/flags/flags.go | 95 ++-- tx-submitter/iface/client.go | 8 +- tx-submitter/iface/rollup.go | 35 +- tx-submitter/mock/event_storage.go | 26 - tx-submitter/mock/l1staking.go | 62 --- tx-submitter/mock/l2client.go | 42 -- tx-submitter/mock/rollup.go | 50 +- tx-submitter/mock/submitter.go | 63 +++ tx-submitter/params/leveldb_keys.go | 5 - tx-submitter/services/batch_fecher.go | 3 +- tx-submitter/services/pendingtx.go | 56 +- tx-submitter/services/pendingtx_test.go | 76 +++ tx-submitter/services/rollup.go | 586 ++++---------------- tx-submitter/services/rollup_handle_test.go | 91 +-- tx-submitter/services/rollup_test.go | 36 +- tx-submitter/services/rotator.go | 158 ------ tx-submitter/types/batch_cache.go | 19 +- tx-submitter/utils/config.go | 105 ++-- tx-submitter/utils/config_test.go | 40 ++ tx-submitter/utils/utils.go | 126 +++-- tx-submitter/utils/utils_test.go | 4 +- 27 files changed, 647 insertions(+), 1400 deletions(-) delete mode 100644 tx-submitter/event/indexer.go delete mode 100644 tx-submitter/event/storage.go delete mode 100644 tx-submitter/event/storage_test.go delete mode 100644 tx-submitter/mock/event_storage.go delete mode 100644 tx-submitter/mock/l1staking.go create mode 100644 tx-submitter/mock/submitter.go delete mode 100644 tx-submitter/params/leveldb_keys.go create mode 100644 tx-submitter/services/pendingtx_test.go delete mode 100644 tx-submitter/services/rotator.go create mode 100644 tx-submitter/utils/config_test.go diff --git a/tx-submitter/README.md b/tx-submitter/README.md index 428197da2..01c4d3fe3 100644 --- a/tx-submitter/README.md +++ b/tx-submitter/README.md @@ -11,6 +11,5 @@ ```bash cast call $ROLLUP_ADDR "lastFinalizedBatchIndex()" -r $L1RPC cast call $ROLLUP_ADDR "lastCommittedBatchIndex()" -r $L1RPC -cast call $L2_SEQUENCER_ADDR "getSequencerSet2()(address[])" -r $L2RPC -cast call $L1_STAKING_ADDR "getActiveStakers()(address[])" -r $L1RPC -``` \ No newline at end of file +cast call $SUBMITTER_ADDR "isActive(address)(bool)" $TX_SUBMITTER_ADDR -r $L1RPC +``` diff --git a/tx-submitter/constants/methods.go b/tx-submitter/constants/methods.go index 7de9eb498..629f87f44 100644 --- a/tx-submitter/constants/methods.go +++ b/tx-submitter/constants/methods.go @@ -3,13 +3,10 @@ package constants const ( // MethodCommitBatch is the method name for committing a batch (with blob when applicable) MethodCommitBatch = "commitBatch" - // MethodCommitState is the method name for recommitting batch state using stored blob hash (no blob in tx) - MethodCommitState = "commitState" // MethodFinalizeBatch is the method name for finalizing a batch MethodFinalizeBatch = "finalizeBatch" ) -// IsCommitLikeMethod returns true for commitBatch or commitState (same calldata shape for batch index parsing). -func IsCommitLikeMethod(method string) bool { - return method == MethodCommitBatch || method == MethodCommitState +func IsOwnedCommitMethod(method string) bool { + return method == MethodCommitBatch } diff --git a/tx-submitter/entry.go b/tx-submitter/entry.go index b67cf0da9..d223b3ce8 100644 --- a/tx-submitter/entry.go +++ b/tx-submitter/entry.go @@ -6,7 +6,6 @@ import ( "crypto/rsa" "fmt" "io" - "math/big" "os" "os/signal" "strings" @@ -14,7 +13,6 @@ import ( "morph-l2/bindings/bindings" "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/metrics" @@ -23,7 +21,6 @@ import ( "morph-l2/tx-submitter/utils" "github.com/morph-l2/externalsign" - "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" @@ -44,18 +41,28 @@ func Main() func(ctx *cli.Context) error { if err != nil { return err } + if cfg.BatchConfigPreflight { + report, err := cfg.BatchConfigReportJSON() + if err != nil { + return fmt.Errorf("encode batch config preflight: %w", err) + } + _, err = fmt.Fprintln(os.Stdout, string(report)) + return err + } // log start info log.Info("starting tx submitter", "l1_rpc", cfg.L1EthRpc, "l2_rpcs", cfg.L2EthRpcs, "rollup_addr", cfg.RollupAddress, - "l2_sequencer_addr", cfg.L2SequencerAddress, - "l2_gov_addr", cfg.L2GovAddress, - "l1_staking_addr", cfg.L1StakingAddress, + "submitter_addr", cfg.SubmitterAddress, + "batch_block_interval_blocks", cfg.BatchBlockInterval, + "batch_timeout_seconds", cfg.BatchTimeout, + "batch_config_hash", cfg.BatchConfig().Hash(), + "batch_config_source_block_number", cfg.BatchConfigSourceBlockNumber, + "batch_config_source_block_hash", cfg.BatchConfigSourceBlockHash, "fee_limit", cfg.TxFeeLimit, "finalize_enable", cfg.Finalize, - "priority_rollup_enable", cfg.PriorityRollup, "rollup_interval", cfg.RollupInterval.String(), "finalize_interval", cfg.FinalizeInterval.String(), "tx_process_interval", cfg.TxProcessInterval.String(), @@ -64,7 +71,6 @@ func Main() func(ctx *cli.Context) error { "journal_path", cfg.JournalFilePath, "gas_rough_estimate", cfg.RoughEstimateGas, "gas_limit_buffer", cfg.GasLimitBuffer, - "rotator_buffer", cfg.RotatorBuffer, "rough_estimate_gas", cfg.RoughEstimateGas, "rough_estimate_base_gas", cfg.RollupTxGasBase, "rough_estimate_per_l1_msg", cfg.RollupTxGasPerL1Msg, @@ -153,10 +159,10 @@ func Main() func(ctx *cli.Context) error { return fmt.Errorf("failed to get rollup abi: %w", err) } - // l1 staking - l1Staking, err := bindings.NewL1Staking(common.HexToAddress(cfg.L1StakingAddress), l1Client) + // L1 submitter qualification contract. + submitter, err := bindings.NewSubmitter(common.HexToAddress(cfg.SubmitterAddress), l1Client) if err != nil { - return fmt.Errorf("failed to connect to l1 staking contract") + return fmt.Errorf("failed to connect to submitter contract: %w", err) } var rsaPriv *rsa.PrivateKey @@ -178,33 +184,10 @@ func Main() func(ctx *cli.Context) error { } - l1StakingAbi, err := bindings.L1StakingMetaData.GetAbi() - if err != nil { - return fmt.Errorf("failed to get l1 staking abi: %w", err) - } - // new event listener - filter := ethereum.FilterQuery{ - Addresses: []common.Address{common.HexToAddress(cfg.L1StakingAddress)}, - Topics: [][]common.Hash{ - {l1StakingAbi.Events["StakersRemoved"].ID}, - }, - } - ldb, err := db.New(cfg.LeveldbPathName) if err != nil { return fmt.Errorf("failed to connect leveldb: %w", err) } - eventInfoStorage := event.NewEventInfoStorage(ldb) - err = eventInfoStorage.Load() - if err != nil { - return err - } - eventIndexer := event.NewEventIndexer(l1Client, new(big.Int).SetUint64(cfg.L1StakingDeployedBlockNumber), filter, cfg.EventIndexStep, eventInfoStorage) - // new rotator - rotator := services.NewRotator(common.HexToAddress(cfg.L2SequencerAddress), common.HexToAddress(cfg.L2GovAddress), eventIndexer) - // start rorator event indexer - rotator.StartEventIndexer() - // block monitor bm := l1checker.NewBlockMonitor(cfg.BlockNotIncreasedThreshold, l1Client) @@ -220,17 +203,15 @@ func Main() func(ctx *cli.Context) error { l1Client, l2Clients, l1Rollup, - l1Staking, + submitter, chainID, privKey, rollupAddr, rollupAbi, cfg, rsaPriv, - rotator, ldb, bm, - eventInfoStorage, l2Caller, ) diff --git a/tx-submitter/event/indexer.go b/tx-submitter/event/indexer.go deleted file mode 100644 index dc517ba72..000000000 --- a/tx-submitter/event/indexer.go +++ /dev/null @@ -1,145 +0,0 @@ -package event - -import ( - "context" - "math/big" - "time" - - "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/ethclient" - "github.com/morph-l2/go-ethereum/log" -) - -type EventIndexer struct { - client *ethclient.Client - deployBlock *big.Int // Block number of contract deployment - filterQuery ethereum.FilterQuery - indexStep uint64 // index step - storage IEventStorage -} - -func NewEventIndexer(client *ethclient.Client, deployedBlock *big.Int, filter ethereum.FilterQuery, indexStep uint64, storage IEventStorage) *EventIndexer { - return &EventIndexer{ - client: client, - deployBlock: deployedBlock, - filterQuery: filter, - indexStep: indexStep, - storage: storage, - } -} - -func (l *EventIndexer) Index() { - log.Info("event indexer started") - - if l.storage.BlockProcessed() == 0 { - l.storage.SetBlockProcessed(l.deployBlock.Uint64()) - err := l.storage.Store() - if err != nil { - log.Error("failed to store initial block number", "error", err) - } - } - - // Create a ticker that triggers every minute - ticker := time.NewTicker(time.Second * 15) - defer ticker.Stop() - - for range ticker.C { - // Get the current block number - currentBlock, err := l.client.BlockNumber(context.Background()) - if err != nil { - log.Error("failed to get current block number", "error", err) - continue - } - - if currentBlock <= l.storage.BlockProcessed() { - log.Info("no new block to index", "current_block", currentBlock, "last_processed_block", l.storage.BlockProcessed()) - continue - } - - // Perform indexing operation - indexedEventInfo, err := l.index(l.client, big.NewInt(int64(l.storage.BlockProcessed())), big.NewInt(int64(currentBlock))) - if err != nil { - log.Error("indexing operation failed", "error", err) - continue - } - - if indexedEventInfo != nil { - l.storage.SetBlockProcessed(indexedEventInfo.BlockProcessed) - } else { - l.storage.SetBlockProcessed(currentBlock) - } - - // Update storage - err = l.storage.Store() - if err != nil { - log.Error("event index complete, failed to update storage", "error", err) - } else { - info := l.storage.EventInfo() - log.Info("event index complete, storage updated", "processed_block", info.BlockProcessed, "block_time", info.BlockTime) - } - } -} - -// filter logs from from_block to to_block -// if the range is too large, will divide the range -func (ei *EventIndexer) index(client *ethclient.Client, fromBlock, toBlock *big.Int) (*EventInfo, error) { - - endBlock := toBlock.Uint64() - startBlock := endBlock - ei.indexStep - lastProcessedBlock := fromBlock.Uint64() - if startBlock < lastProcessedBlock { - startBlock = lastProcessedBlock - } - logFilter := ei.GetFilter() - - // Find the last unprocessed log - for endBlock >= lastProcessedBlock && endBlock > startBlock { - logFilter.FromBlock = big.NewInt(int64(startBlock)) - logFilter.ToBlock = big.NewInt(int64(endBlock)) - historicalLogs, err := client.FilterLogs(context.Background(), logFilter) - if err != nil { - log.Error("Failed to get historical logs", - "error", err, - "start_block", startBlock, - "end_block", endBlock, - ) - continue - } else { - if len(historicalLogs) > 0 { - latestLog := historicalLogs[len(historicalLogs)-1] - var block *types.Block - for { - block, err = client.BlockByNumber(context.Background(), new(big.Int).SetUint64(latestLog.BlockNumber)) - if err != nil { - log.Error("Failed to get block", "error", err) - time.Sleep(time.Second * 5) - continue - } else { - return &EventInfo{ - BlockProcessed: toBlock.Uint64(), - BlockTime: block.Time(), - }, nil - } - } - } - log.Info("backward indexing", "block_num", startBlock, "target_num", lastProcessedBlock) - // update query range - endBlock = startBlock - if endBlock <= lastProcessedBlock+ei.indexStep { - startBlock = lastProcessedBlock + 1 - } else { - startBlock = endBlock - ei.indexStep - } - - } - } - return nil, nil -} - -func (l *EventIndexer) GetFilter() ethereum.FilterQuery { - return l.filterQuery -} -func (l *EventIndexer) GetStorage() IEventStorage { - return l.storage -} diff --git a/tx-submitter/event/storage.go b/tx-submitter/event/storage.go deleted file mode 100644 index dcec97af0..000000000 --- a/tx-submitter/event/storage.go +++ /dev/null @@ -1,109 +0,0 @@ -package event - -import ( - "encoding/json" - "errors" - "fmt" - "sync" - - "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/params" -) - -type IEventStorage interface { - Store() error - Load() error - BlockProcessed() uint64 - SetBlockProcessed(blockNum uint64) - BlockTime() uint64 - SetBlockTime(blockTime uint64) - EventInfo() EventInfo -} - -type EventInfo struct { - BlockTime uint64 `json:"block_time"` // event emit time - BlockProcessed uint64 `json:"block_processed"` // block processed -} - -type EventInfoStorage struct { - eventInfo EventInfo - db db.Database - mu sync.RWMutex -} - -func NewEventInfoStorage(db db.Database) *EventInfoStorage { - return &EventInfoStorage{ - db: db, - } -} - -func (e *EventInfoStorage) Store() error { - // Convert struct to JSON string - jsonData, err := json.Marshal(e.eventInfo) - if err != nil { - return fmt.Errorf("failed to convert struct to JSON: %w", err) - } - - e.mu.Lock() - defer e.mu.Unlock() - // Write JSON data to file - err = e.db.PutString(params.EventInfoKey, string(jsonData)) - if err != nil { - return fmt.Errorf("failed to write to db: err=%w, data=%v", err, jsonData) - } - return nil -} - -func (e *EventInfoStorage) Load() error { - e.mu.Lock() - defer e.mu.Unlock() - - jsonStr, err := e.db.GetString(params.EventInfoKey) - if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { - // Initialize with default values if not found - e.eventInfo = EventInfo{} - return nil - } - return fmt.Errorf("failed to read from db: %w", err) - } - - err = json.Unmarshal([]byte(jsonStr), &e.eventInfo) - if err != nil { - return fmt.Errorf("failed to parse JSON: %w", err) - } - - return nil -} - -func (e *EventInfoStorage) BlockProcessed() uint64 { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo.BlockProcessed -} - -func (e *EventInfoStorage) SetBlockProcessed(blockNum uint64) { - e.mu.Lock() - defer e.mu.Unlock() - e.eventInfo.BlockProcessed = blockNum -} - -func (e *EventInfoStorage) BlockTime() uint64 { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo.BlockTime -} - -func (e *EventInfoStorage) SetBlockTime(blockTime uint64) { - e.mu.Lock() - defer e.mu.Unlock() - e.eventInfo.BlockTime = blockTime -} - -// EventInfo returns a copy of the current event info. -// This ensures thread safety without exposing the internal state. -func (e *EventInfoStorage) EventInfo() EventInfo { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo -} diff --git a/tx-submitter/event/storage_test.go b/tx-submitter/event/storage_test.go deleted file mode 100644 index 2299bab52..000000000 --- a/tx-submitter/event/storage_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package event - -import ( - "morph-l2/tx-submitter/db" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestEventInfoStorage(t *testing.T) { - // Create a unique test directory - testDir := filepath.Join(t.TempDir(), "testleveldb") - - // Cleanup before test (in case it exists) - os.RemoveAll(testDir) - - // Cleanup after test - t.Cleanup(func() { - os.RemoveAll(testDir) - }) - - db, err := db.New(testDir) - require.NoError(t, err) - storage := NewEventInfoStorage(db) - err = storage.Load() - require.NoError(t, err) - - storage.SetBlockTime(100) - storage.SetBlockProcessed(100) - err = storage.Store() - require.NoError(t, err) - - storage2 := NewEventInfoStorage(db) - err = storage2.Load() - require.NoError(t, err) - require.Equal(t, storage.BlockTime(), storage2.BlockTime()) - require.Equal(t, storage.BlockProcessed(), storage2.BlockProcessed()) -} diff --git a/tx-submitter/flags/flags.go b/tx-submitter/flags/flags.go index cdbf1405d..568fe1637 100644 --- a/tx-submitter/flags/flags.go +++ b/tx-submitter/flags/flags.go @@ -3,8 +3,6 @@ package flags import ( "time" - "morph-l2/bindings/predeploys" - "github.com/urfave/cli" ) @@ -59,11 +57,11 @@ var ( Required: true, EnvVar: prefixEnvVar("ROLLUP_ADDRESS"), } - L1StakingAddressFlag = cli.StringFlag{ - Name: "l1_staking_address", - Usage: "Address of the staking contract", + SubmitterAddressFlag = cli.StringFlag{ + Name: "submitter_address", + Usage: "Address of the Submitter qualification and stake contract", Required: true, - EnvVar: prefixEnvVar("L1_STAKING_ADDRESS"), + EnvVar: prefixEnvVar("SUBMITTER_ADDRESS"), } // finalize flags @@ -74,28 +72,17 @@ var ( Required: true, } - // decentralize config - PriorityRollupFlag = cli.BoolFlag{ - Name: "priority_rollup", - Usage: "Enable priority rollup", - EnvVar: prefixEnvVar("PRIORITY_ROLLUP"), + BatchBlockIntervalFlag = cli.Uint64Flag{ + Name: "batch_block_interval", + Usage: "Static batch sealing interval in L2 blocks (may be zero if timeout is non-zero)", + EnvVar: prefixEnvVar("BATCH_BLOCK_INTERVAL"), Required: true, } - - // L2 contract - L2SequencerAddressFlag = cli.StringFlag{ - Name: "l2_sequencer_address", - Usage: "Address of the sequencer contract", - Required: false, - EnvVar: prefixEnvVar("L2_SEQUENCER_ADDRESS"), - Value: predeploys.Sequencer, - } - L2GovAddressFlag = cli.StringFlag{ - Name: "l2_gov_address", - Usage: "Address of the gov contract", - Required: false, - EnvVar: prefixEnvVar("L2_GOV_ADDRESS"), - Value: predeploys.Gov, + BatchTimeoutFlag = cli.Uint64Flag{ + Name: "batch_timeout", + Usage: "Static batch sealing timeout in seconds (may be zero if interval is non-zero)", + EnvVar: prefixEnvVar("BATCH_TIMEOUT"), + Required: true, } /* Optional Flags */ @@ -206,12 +193,20 @@ var ( EnvVar: prefixEnvVar("JOURNAL_FILE_PATH"), Value: "journal.rlp", } - // listener processed block record path - StakingEventStoreFileFlag = cli.StringFlag{ - Name: "staking_event_store_filename", - Usage: "The file name of the storage", - EnvVar: prefixEnvVar("STAKING_EVENT_STORE_FILENAME"), - Value: "StakingEventStore.json", + BatchConfigPreflightFlag = cli.BoolFlag{ + Name: "batch_config_preflight", + Usage: "Print the effective static batch configuration and hash, then exit", + EnvVar: prefixEnvVar("BATCH_CONFIG_PREFLIGHT"), + } + BatchConfigSourceBlockNumberFlag = cli.Uint64Flag{ + Name: "batch_config_source_block_number", + Usage: "L2 block number at which the static batch values were snapshotted", + EnvVar: prefixEnvVar("BATCH_CONFIG_SOURCE_BLOCK_NUMBER"), + } + BatchConfigSourceBlockHashFlag = cli.StringFlag{ + Name: "batch_config_source_block_hash", + Usage: "L2 block hash at which the static batch values were snapshotted", + EnvVar: prefixEnvVar("BATCH_CONFIG_SOURCE_BLOCK_HASH"), } TipFeeBumpFlag = cli.Uint64Flag{ @@ -288,28 +283,6 @@ var ( EnvVar: prefixEnvVar("ROUGH_ESTIMATE_GAS"), } - RotatorBufferFlag = cli.Int64Flag{ - Name: "rotator_buffer", - Usage: "rotation interval buffer", - Value: 15, - EnvVar: prefixEnvVar("ROTATOR_BUFFER"), - } - - // l1 staking deployed blocknum - L1StakingDeployedBlocknumFlag = cli.Uint64Flag{ - Name: "l1_staking_deployed_blocknum", - Usage: "The deployed block number of L1Staking", - EnvVar: prefixEnvVar("L1_STAKING_DEPLOYED_BLOCKNUM"), - Required: true, - } - - // event indexer - EventIndexStepFlag = cli.Uint64Flag{ - Name: "event_index_step", - Usage: "The step size for event indexing", - Value: 100, - EnvVar: prefixEnvVar("EVENT_INDEX_STEP"), - } LeveldbPathNameFlag = cli.StringFlag{ Name: "leveldb_path_name", Usage: "The path name of the leveldb", @@ -356,10 +329,10 @@ var requiredFlags = []cli.Flag{ RollupAddressFlag, TxTimeoutFlag, FinalizeFlag, - PriorityRollupFlag, TxFeeLimitFlag, - L1StakingAddressFlag, - L1StakingDeployedBlocknumFlag, + SubmitterAddressFlag, + BatchBlockIntervalFlag, + BatchTimeoutFlag, } var optionalFlags = []cli.Flag{ @@ -382,10 +355,11 @@ var optionalFlags = []cli.Flag{ GasLimitBuffer, JournalFlag, + BatchConfigPreflightFlag, + BatchConfigSourceBlockNumberFlag, + BatchConfigSourceBlockHashFlag, PrivateKeyFlag, - L2SequencerAddressFlag, - L2GovAddressFlag, TipFeeBumpFlag, MaxTipFlag, MinTipFlag, @@ -400,9 +374,6 @@ var optionalFlags = []cli.Flag{ ExternalSignUrl, ExternalSignRsaPriv, RoughEstimateGasFlag, - RotatorBufferFlag, - StakingEventStoreFileFlag, - EventIndexStepFlag, LeveldbPathNameFlag, BlockNotIncreasedThreshold, diff --git a/tx-submitter/iface/client.go b/tx-submitter/iface/client.go index 2081355db..228dd1e4e 100644 --- a/tx-submitter/iface/client.go +++ b/tx-submitter/iface/client.go @@ -254,14 +254,14 @@ func (c *L2Clients) GetBlockTraceByNumber(ctx context.Context, number *big.Int) func (c *L2Clients) GetRollupBatchByIndex(ctx context.Context, batchIndex uint64) (*eth.RPCRollupBatch, error) { var result *eth.RPCRollupBatch err := c.tryAllClients(func(client L2Client) error { - var err error - result, err = client.GetRollupBatchByIndex(ctx, batchIndex) + candidate, err := client.GetRollupBatchByIndex(ctx, batchIndex) if err != nil { return err } - if result != nil && len(result.Signatures) > 0 { - return nil + if candidate == nil { + return errors.New("rollup batch not found") } + result = candidate return nil }) diff --git a/tx-submitter/iface/rollup.go b/tx-submitter/iface/rollup.go index 9a60a64b5..6ee543c6b 100644 --- a/tx-submitter/iface/rollup.go +++ b/tx-submitter/iface/rollup.go @@ -11,41 +11,32 @@ import ( ) type IRollup interface { + BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) - CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) + CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput) (*types.Transaction, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) + FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) + MessageQueue(opts *bind.CallOpts) (common.Address, error) FinalizeBatch(*bind.TransactOpts, []byte) (*types.Transaction, error) BatchInsideChallengeWindow(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) BatchExist(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) - BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) FilterCommitBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupCommitBatchIterator, error) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) + FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) } -// IL2Sequencer is the interface for the sequencer on L2 -type IL2Sequencer interface { - SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) -} - -type IL2Gov interface { - RollupEpoch(opts *bind.CallOpts) (*big.Int, error) - BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) - BatchTimeout(opts *bind.CallOpts) (*big.Int, error) -} - -type IL1Staking interface { - IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) - GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) - GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) - GetStakers(opts *bind.CallOpts) ([255]common.Address, error) +// ISubmitter is the minimum qualification surface required by the official +// submitter. Selection/rotation is deliberately not part of this interface. +type ISubmitter interface { + IsActive(opts *bind.CallOpts, addr common.Address) (bool, error) } type IL2MessagePasser interface { diff --git a/tx-submitter/mock/event_storage.go b/tx-submitter/mock/event_storage.go deleted file mode 100644 index e26087720..000000000 --- a/tx-submitter/mock/event_storage.go +++ /dev/null @@ -1,26 +0,0 @@ -package mock - -import ( - "morph-l2/tx-submitter/event" -) - -// MockEventInfoStorage is a mock implementation of the EventInfoStorage -type MockEventInfoStorage struct { - event.EventInfoStorage -} - -// NewMockEventInfoStorage creates a new mock EventInfoStorage -func NewMockEventInfoStorage() *event.EventInfoStorage { - mockDB := NewMockDB() - return event.NewEventInfoStorage(mockDB) -} - -// Store implements the Store method -func (m *MockEventInfoStorage) Store() error { - return nil -} - -// Load implements the Load method -func (m *MockEventInfoStorage) Load() error { - return nil -} diff --git a/tx-submitter/mock/l1staking.go b/tx-submitter/mock/l1staking.go deleted file mode 100644 index 08939b834..000000000 --- a/tx-submitter/mock/l1staking.go +++ /dev/null @@ -1,62 +0,0 @@ -package mock - -import ( - "math/big" - - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" -) - -// MockL1Staking is a mock implementation of IL1Staking -type MockL1Staking struct { - activeStakers []common.Address -} - -// NewMockL1Staking creates a new mock L1Staking instance -func NewMockL1Staking() *MockL1Staking { - return &MockL1Staking{ - activeStakers: []common.Address{}, - } -} - -// IsStaker implements IL1Staking -func (m *MockL1Staking) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - for _, staker := range m.activeStakers { - if staker == addr { - return true, nil - } - } - return false, nil -} - -// GetStakersBitmap implements IL1Staking -func (m *MockL1Staking) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { - bitmap := big.NewInt(0) - for i, staker := range _stakers { - for _, activeStaker := range m.activeStakers { - if staker == activeStaker { - bitmap.SetBit(bitmap, i, 1) - } - } - } - return bitmap, nil -} - -// GetActiveStakers implements IL1Staking -func (m *MockL1Staking) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { - return m.activeStakers, nil -} - -// GetStakers implements IL1Staking -func (m *MockL1Staking) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { - var result [255]common.Address - for i := 0; i < len(m.activeStakers) && i < 255; i++ { - result[i] = m.activeStakers[i] - } - return result, nil -} - -// SetActiveStakers sets the active stakers for testing -func (m *MockL1Staking) SetActiveStakers(stakers []common.Address) { - m.activeStakers = stakers -} diff --git a/tx-submitter/mock/l2client.go b/tx-submitter/mock/l2client.go index d1acf1b8a..c73e1c816 100644 --- a/tx-submitter/mock/l2client.go +++ b/tx-submitter/mock/l2client.go @@ -3,7 +3,6 @@ package mock import ( "context" "math/big" - "time" "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" @@ -21,27 +20,16 @@ type L2ClientWrapper struct { TipCap *big.Int reorgDepth int64 reorgCount int64 - sequencerSet []common.Address BaseFee *big.Int } func NewL2ClientWrapper() *L2ClientWrapper { - // Create mock CallContractResult for epoch update time - // Return a timestamp from 1 hour ago - timestamp := time.Now().Add(-1 * time.Hour).Unix() result := make([]byte, 32) - big.NewInt(timestamp).FillBytes(result) - - // Create a mock sequencer set with two addresses - mockAddr1 := common.HexToAddress("0x1111111111111111111111111111111111111111") - mockAddr2 := common.HexToAddress("0x2222222222222222222222222222222222222222") - sequencerSet := []common.Address{mockAddr1, mockAddr2} return &L2ClientWrapper{ TipCap: big.NewInt(1e9), Balance: big.NewInt(1e18), CallContractResult: result, - sequencerSet: sequencerSet, BaseFee: big.NewInt(1e9), } } @@ -52,31 +40,6 @@ func (l *L2ClientWrapper) CallContract(ctx context.Context, msg ethereum.CallMsg return nil, l.CallContractErr } - // If calling the sequencer set method, return the mock sequencer set - if len(msg.Data) >= 4 { - methodID := msg.Data[:4] - // Method ID for GetSequencerSet2() - if string(methodID) == "\x77\xd7\xdf\xfb" { - // Encode the sequencer set into bytes - result := make([]byte, 0) - // First 32 bytes for offset - offset := make([]byte, 32) - big.NewInt(32).FillBytes(offset) - result = append(result, offset...) - // Next 32 bytes for length - length := make([]byte, 32) - big.NewInt(int64(len(l.sequencerSet))).FillBytes(length) - result = append(result, length...) - // Then the addresses - for _, addr := range l.sequencerSet { - addrBytes := make([]byte, 32) - copy(addrBytes[12:], addr.Bytes()) - result = append(result, addrBytes...) - } - return result, nil - } - } - return l.CallContractResult, nil } @@ -207,8 +170,3 @@ func (l *L2ClientWrapper) SuggestGasTipCap(ctx context.Context) (*big.Int, error } return big.NewInt(1e9), nil } - -// GetSequencerSet2 implements IL2Sequencer -func (m *L2ClientWrapper) GetSequencerSet2() ([]common.Address, error) { - return m.sequencerSet, nil -} diff --git a/tx-submitter/mock/rollup.go b/tx-submitter/mock/rollup.go index cf889c6a4..6542fc38e 100644 --- a/tx-submitter/mock/rollup.go +++ b/tx-submitter/mock/rollup.go @@ -7,6 +7,7 @@ import ( "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" "morph-l2/bindings/bindings" ) @@ -21,6 +22,16 @@ type MockRollup struct { finalizeTx *types.Transaction } +// BatchBlobVersionedHashes implements IRollup. +func (m *MockRollup) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { + return [32]byte{}, nil +} + +// MessageQueue implements IRollup. +func (m *MockRollup) MessageQueue(opts *bind.CallOpts) (common.Address, error) { + return common.Address{}, nil +} + // NewMockRollup creates a new instance of MockRollup func NewMockRollup() *MockRollup { return &MockRollup{ @@ -37,10 +48,14 @@ func (m *MockRollup) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, err } // CommitBatch implements IRollup -func (m *MockRollup) CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) { +func (m *MockRollup) CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput) (*types.Transaction, error) { return m.batchTx, nil } +func (m *MockRollup) FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { + return [32]byte{}, nil +} + // LastFinalizedBatchIndex implements IRollup func (m *MockRollup) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) { return m.lastFinalizedBatchIndex, nil @@ -66,28 +81,22 @@ func (m *MockRollup) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) return [32]byte{}, nil } -// BatchBlobVersionedHashes implements IRollup (no stored hash by default) -func (m *MockRollup) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { - return [32]byte{}, nil -} - // BatchDataStore implements IRollup func (m *MockRollup) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }{ - OriginTimestamp: big.NewInt(0), - FinalizeTimestamp: big.NewInt(0), - BlockNumber: big.NewInt(0), - SignedSequencersBitmap: big.NewInt(0), + OriginTimestamp: big.NewInt(0), + FinalizeTimestamp: big.NewInt(0), + BlockNumber: big.NewInt(0), }, nil } @@ -101,6 +110,11 @@ func (m *MockRollup) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*bi return nil, nil } +// FilterRevertBatch implements IRollup. +func (m *MockRollup) FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) { + return nil, errors.New("FilterRevertBatch not implemented in mock") +} + // SetLastCommittedBatchIndex sets the mock value for LastCommittedBatchIndex func (m *MockRollup) SetLastCommittedBatchIndex(index *big.Int) { m.lastCommittedBatchIndex = index diff --git a/tx-submitter/mock/submitter.go b/tx-submitter/mock/submitter.go new file mode 100644 index 000000000..03a760318 --- /dev/null +++ b/tx-submitter/mock/submitter.go @@ -0,0 +1,63 @@ +package mock + +import ( + "sync" + + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" +) + +// MockSubmitter implements the minimal submitter qualification view used by +// the transaction submitter. +type MockSubmitter struct { + mu sync.RWMutex + active map[common.Address]bool + defaultOn bool + lastQuery common.Address + err error +} + +func NewMockSubmitter() *MockSubmitter { + return &MockSubmitter{ + active: make(map[common.Address]bool), + defaultOn: true, + } +} + +func (m *MockSubmitter) IsActive(_ *bind.CallOpts, addr common.Address) (bool, error) { + m.mu.Lock() + defer m.mu.Unlock() + m.lastQuery = addr + if m.err != nil { + return false, m.err + } + active, configured := m.active[addr] + if !configured { + return m.defaultOn, nil + } + return active, nil +} + +func (m *MockSubmitter) SetActive(addr common.Address, active bool) { + m.mu.Lock() + defer m.mu.Unlock() + m.active[addr] = active +} + +func (m *MockSubmitter) SetDefaultActive(active bool) { + m.mu.Lock() + defer m.mu.Unlock() + m.defaultOn = active +} + +func (m *MockSubmitter) SetError(err error) { + m.mu.Lock() + defer m.mu.Unlock() + m.err = err +} + +func (m *MockSubmitter) LastQuery() common.Address { + m.mu.RLock() + defer m.mu.RUnlock() + return m.lastQuery +} diff --git a/tx-submitter/params/leveldb_keys.go b/tx-submitter/params/leveldb_keys.go deleted file mode 100644 index b998e6de9..000000000 --- a/tx-submitter/params/leveldb_keys.go +++ /dev/null @@ -1,5 +0,0 @@ -package params - -const ( - EventInfoKey = "event_info" -) diff --git a/tx-submitter/services/batch_fecher.go b/tx-submitter/services/batch_fecher.go index 7c658ab81..f87b11fdc 100644 --- a/tx-submitter/services/batch_fecher.go +++ b/tx-submitter/services/batch_fecher.go @@ -27,8 +27,7 @@ func (bf *BatchFetcher) GetRollupBatchByIndex(index uint64) (*eth.RPCRollupBatch lastErr = err continue } - // Validate that batch exists and has signatures before returning - if batch != nil && len(batch.Signatures) > 0 { + if batch != nil { return batch, nil } } diff --git a/tx-submitter/services/pendingtx.go b/tx-submitter/services/pendingtx.go index b94735b94..02632003a 100644 --- a/tx-submitter/services/pendingtx.go +++ b/tx-submitter/services/pendingtx.go @@ -1,6 +1,7 @@ package services import ( + "bytes" "fmt" "sort" "sync" @@ -40,7 +41,7 @@ type PendingTxs struct { } // NewPendingTxs creates a new PendingTxs instance. -// Commit-like txs (commitBatch / commitState) are detected via utils.ParseMethod + constants.IsCommitLikeMethod, not stored method IDs. +// Only current commitBatch transactions are owned by this process. func NewPendingTxs(journal Journal) *PendingTxs { return &PendingTxs{ txinfos: make(map[common.Hash]*types.TxRecord), @@ -221,8 +222,11 @@ func (pt *PendingTxs) ExistedIndex(index uint64) bool { for i := len(txs) - 1; i >= 0; i-- { tx := txs[i].Tx - if constants.IsCommitLikeMethod(utils.ParseMethod(tx, abi)) { - pindex := utils.ParseParentBatchIndex(tx.Data()) + 1 + if constants.IsOwnedCommitMethod(utils.ParseMethod(tx, abi)) { + pindex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), abi) + if err != nil { + continue + } if index == pindex { return true } @@ -242,20 +246,40 @@ func (pt *PendingTxs) Recover(txs []*ethtypes.Transaction, abi *abi.ABI) error { var maxCommitBatchIndex, maxFinalizeBatchIndex uint64 for _, tx := range txs { - // Get method name - method := utils.ParseMethod(tx, abi) - - // Get batch index based on method + method := "cancel" var batchIndex uint64 - if constants.IsCommitLikeMethod(method) { - batchIndex = utils.ParseParentBatchIndex(tx.Data()) + 1 - if batchIndex > maxCommitBatchIndex { - maxCommitBatchIndex = batchIndex - } - } else if method == constants.MethodFinalizeBatch { - batchIndex = utils.ParseFBatchIndex(tx.Data()) - if batchIndex > maxFinalizeBatchIndex { - maxFinalizeBatchIndex = batchIndex + var err error + finalizeMethod, hasFinalizeMethod := abi.Methods[constants.MethodFinalizeBatch] + if len(tx.Data()) != 0 { + ownedMethod, _, ownedErr := utils.ParseOwnedCommit(tx.Data(), abi) + switch { + case ownedErr == nil: + method = ownedMethod + if tx.Type() != ethtypes.BlobTxType || tx.BlobTxSidecar() == nil || len(tx.BlobTxSidecar().Blobs) == 0 || len(tx.BlobHashes()) == 0 { + return fmt.Errorf("owned commit journal entry %s is missing its blob sidecar; use a fresh data directory", tx.Hash()) + } + batchIndex, err = utils.ParseOwnedCommitBatchIndex(tx.Data(), abi) + if err != nil { + return fmt.Errorf("invalid owned commit journal entry %s: %w", tx.Hash(), err) + } + if batchIndex > maxCommitBatchIndex { + maxCommitBatchIndex = batchIndex + } + case hasFinalizeMethod && len(tx.Data()) >= 4 && bytes.Equal(tx.Data()[:4], finalizeMethod.ID): + method = constants.MethodFinalizeBatch + if _, err := finalizeMethod.Inputs.Unpack(tx.Data()[4:]); err != nil { + return fmt.Errorf("invalid finalize journal entry %s: %w", tx.Hash(), err) + } + batchIndex = utils.ParseFBatchIndex(tx.Data()) + if batchIndex > maxFinalizeBatchIndex { + maxFinalizeBatchIndex = batchIndex + } + default: + selector := tx.Data() + if len(selector) > 4 { + selector = selector[:4] + } + return fmt.Errorf("unsupported legacy or unknown journal calldata in tx %s (selector 0x%x); use a fresh data directory", tx.Hash(), selector) } } diff --git a/tx-submitter/services/pendingtx_test.go b/tx-submitter/services/pendingtx_test.go new file mode 100644 index 000000000..370f1a0ad --- /dev/null +++ b/tx-submitter/services/pendingtx_test.go @@ -0,0 +1,76 @@ +package services + +import ( + "encoding/binary" + "encoding/hex" + "math/big" + "testing" + + "github.com/holiman/uint256" + "github.com/morph-l2/go-ethereum/common" + ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto/kzg4844" + "github.com/stretchr/testify/require" + + "morph-l2/bindings/bindings" + "morph-l2/tx-submitter/mock" +) + +func TestPendingTxsRecoverRejectsNonOwnedCalldata(t *testing.T) { + current, err := bindings.RollupMetaData.GetAbi() + require.NoError(t, err) + + selectors := map[string]string{ + "pre submitter commitBatch": "428868b5", + "pre submitter commitState": "1e8825be", + "pre submitter commitBatchWithProof": "4e8f1d67", + "unknown": "deadbeef", + } + selectors["current commitState"] = hex.EncodeToString(current.Methods["commitState"].ID) + selectors["current commitBatchWithProof"] = hex.EncodeToString(current.Methods["commitBatchWithProof"].ID) + + for name, selector := range selectors { + t.Run(name, func(t *testing.T) { + data, err := hex.DecodeString(selector) + require.NoError(t, err) + tx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ + ChainID: big.NewInt(1), + To: &common.Address{}, + Data: data, + }) + pending := NewPendingTxs(mock.NewMockJournal()) + err = pending.Recover([]*ethtypes.Transaction{tx}, current) + require.ErrorContains(t, err, "legacy or unknown journal calldata") + require.Zero(t, pending.Len()) + }) + } +} + +func TestPendingTxsRecoverAcceptsCurrentFreshBlobCommit(t *testing.T) { + current, err := bindings.RollupMetaData.GetAbi() + require.NoError(t, err) + require.Equal(t, "41f756da", hex.EncodeToString(current.Methods["commitBatch"].ID)) + + parentHeader := make([]byte, 9) + binary.BigEndian.PutUint64(parentHeader[1:], 7) + calldata, err := current.Pack("commitBatch", bindings.IRollupBatchDataInput{ + ParentBatchHeader: parentHeader, + }) + require.NoError(t, err) + + tx := ethtypes.NewTx(ðtypes.BlobTx{ + ChainID: uint256.NewInt(1), + To: common.Address{}, + Data: calldata, + BlobFeeCap: uint256.NewInt(1), + BlobHashes: []common.Hash{{1}}, + Sidecar: ðtypes.BlobTxSidecar{ + Blobs: []kzg4844.Blob{{1}}, + Commitments: []kzg4844.Commitment{{1}}, + }, + }) + pending := NewPendingTxs(mock.NewMockJournal()) + require.NoError(t, pending.Recover([]*ethtypes.Transaction{tx}, current)) + require.Equal(t, 1, pending.Len()) + require.Equal(t, uint64(8), pending.GetPindex()) +} diff --git a/tx-submitter/services/rollup.go b/tx-submitter/services/rollup.go index 2df98cffd..34a9a9c66 100644 --- a/tx-submitter/services/rollup.go +++ b/tx-submitter/services/rollup.go @@ -30,7 +30,6 @@ import ( "morph-l2/common/blob" "morph-l2/tx-submitter/constants" "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/localpool" @@ -42,26 +41,23 @@ import ( const ( txSlotSize = 32 * 1024 txMaxSize = 4 * txSlotSize // 128KB - rotatorWait = 3 * time.Second rollupSumKey = "rollup_sum" finalizeSumKey = "finalize_sum" collectedL1FeeSumKey = "collected_l1_fee_sum" ) type Rollup struct { - ctx context.Context - metrics *metrics.Metrics - l1RpcClient *rpc.Client - L1Client iface.Client - L2Clients []iface.L2Client - Rollup iface.IRollup - Staking iface.IL1Staking - chainId *big.Int - privKey *ecdsa.PrivateKey - rollupAddr common.Address - abi *abi.ABI - // rotator - rotator *Rotator + ctx context.Context + metrics *metrics.Metrics + l1RpcClient *rpc.Client + L1Client iface.Client + L2Clients []iface.L2Client + Rollup iface.IRollup + Submitter iface.ISubmitter + chainId *big.Int + privKey *ecdsa.PrivateKey + rollupAddr common.Address + abi *abi.ABI pendingTxs *PendingTxs rollupFinalizeMu sync.Mutex externalRsaPriv *rsa.PrivateKey @@ -81,7 +77,6 @@ type Rollup struct { batchCache *batch.BatchCache batchCacheLegacy *types.BatchCacheLegacy bm *l1checker.BlockMonitor - eventInfoStorage *event.EventInfoStorage reorgDetector iface.IReorgDetector ChainConfigMap blob.ChainBlobConfigs @@ -94,17 +89,15 @@ func NewRollup( l1 iface.Client, l2Clients []iface.L2Client, rollup iface.IRollup, - staking iface.IL1Staking, + submitter iface.ISubmitter, chainId *big.Int, priKey *ecdsa.PrivateKey, rollupAddr common.Address, abi *abi.ABI, cfg utils.Config, rsaPriv *rsa.PrivateKey, - rotator *Rotator, ldb *db.Db, bm *l1checker.BlockMonitor, - eventInfoStorage *event.EventInfoStorage, l2Caller *types.L2Caller, ) *Rollup { reorgDetector := NewReorgDetector(l1) @@ -114,13 +107,12 @@ func NewRollup( l1RpcClient: l1RpcClient, L1Client: l1, Rollup: rollup, - Staking: staking, + Submitter: submitter, L2Clients: l2Clients, privKey: priKey, chainId: chainId, rollupAddr: rollupAddr, abi: abi, - rotator: rotator, cfg: cfg, signer: ethtypes.LatestSignerForChainID(chainId), externalRsaPriv: rsaPriv, @@ -130,17 +122,17 @@ func NewRollup( return cfg.BatchV2UpgradeTime > 0 && blockTimestamp >= cfg.BatchV2UpgradeTime }, cfg.MaxBlobCount, + cfg.BatchConfig(), l1, &iface.L2Clients{Clients: l2Clients}, rollup, l2Caller, ldb, ), - ldb: ldb, - bm: bm, - eventInfoStorage: eventInfoStorage, - reorgDetector: reorgDetector, - ChainConfigMap: blob.ChainConfigMap, + ldb: ldb, + bm: bm, + reorgDetector: reorgDetector, + ChainConfigMap: blob.ChainConfigMap, } if !cfg.SealBatch { fetcher := NewBatchFetcher(l2Clients) @@ -156,26 +148,38 @@ func (r *Rollup) Start() error { return err } + // Cold start is synchronous and fail-closed. On an empty database this + // reconstructs the finalized anchor and committed range from canonical L1, + // then packs every L2 block through the observed head before any journal or + // submission loop is created. + if r.cfg.SealBatch { + if err := r.batchCache.InitAndSyncFromDatabase(); err != nil { + return r.rollbackCanonicalBootstrap("initialize batch cache from canonical state", err) + } + if err := r.batchCache.AssembleCurrentBatchHeader(); err != nil { + return r.rollbackCanonicalBootstrap("assemble downtime L2 blocks", err) + } + } + // journal jn := localpool.New(r.cfg.JournalFilePath) - err := jn.Init() - if err != nil { - log.Crit("journal file init failed", "err", err) + if err := jn.Init(); err != nil { + return r.failStartup("journal file init failed", err) } // pendingtxs r.pendingTxs = NewPendingTxs(jn) txs, err := jn.ParseAllTxs() if err != nil { - log.Crit("parse l1 mempool error", "error", err) + return r.failStartup("parse pending transaction journal", err) } if err := r.pendingTxs.Recover(txs, r.abi); err != nil { - log.Crit("failed to recover pending transactions", "error", err) + return r.failStartup("recover pending transactions", err) } // init fee metrics sum err = r.InitFeeMetricsSum() if err != nil { - return fmt.Errorf("init fee metrics sum failed: %w", err) + return r.failStartup("init fee metrics sum failed", err) } /// start services @@ -274,21 +278,6 @@ func (r *Rollup) Start() error { if r.cfg.SealBatch { var batchCacheSyncMu sync.Mutex - - go func() { - batchCacheSyncMu.Lock() - defer batchCacheSyncMu.Unlock() - for { - - if err = r.batchCache.InitAndSyncFromDatabase(); err != nil { - log.Error("init and sync from database failed, wait for the next try", "error", err) - time.Sleep(5 * time.Second) - continue - } - break - } - }() - go utils.Loop(r.ctx, r.cfg.TxProcessInterval, func() { batchCacheSyncMu.Lock() defer batchCacheSyncMu.Unlock() @@ -308,6 +297,20 @@ func (r *Rollup) Start() error { return nil } +func (r *Rollup) rollbackCanonicalBootstrap(stage string, cause error) error { + if resetErr := r.batchCache.ResetCanonicalBootstrap(); resetErr != nil { + return fmt.Errorf("%s: %v; rollback canonical bootstrap: %w", stage, cause, resetErr) + } + return fmt.Errorf("%s: %w", stage, cause) +} + +func (r *Rollup) failStartup(stage string, cause error) error { + if r.cfg.SealBatch { + return r.rollbackCanonicalBootstrap(stage, cause) + } + return fmt.Errorf("%s: %w", stage, cause) +} + func (r *Rollup) ProcessTx() error { // Check for reorgs first with exponential backoff retry hasReorg, depth, err := r.detectReorgWithRetry() @@ -326,45 +329,6 @@ func (r *Rollup) ProcessTx() error { return nil } - // Check if this submitter should process transactions - if err = r.checkSubmitterTurn(); err != nil { - if errors.Is(err, errNotMyTurn) { - // If rotator is not configured or not yet initialized, just skip this round safely. - if r.rotator == nil || r.rotator.startTime == nil || r.rotator.epoch == nil { - log.Info("Awaiting turn for transaction processing, but rotator state is not initialized", - "has_rotator", r.rotator != nil) - return nil - } - - // Get current submitter index for logging - activeSubmitter, activeIndex, rotErr := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if rotErr != nil || activeSubmitter == nil { - log.Warn("Failed to get current submitter while awaiting turn", - "error", rotErr) - return nil - } - - // Calculate rotation timing information - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - timeLeft := end - time.Now().Unix() - - // Format timestamps for human readability - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - log.Info("Awaiting turn for transaction processing", - "current_submitter", activeSubmitter.Hex(), - "submitter_index", activeIndex, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "next_rotation", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return nil - } - return err - } - // Process each transaction for _, txRecord := range txRecords { if err := r.processSingleTx(txRecord); err != nil { @@ -392,59 +356,6 @@ func (r *Rollup) detectReorgWithRetry() (bool, uint64, error) { return false, 0, lastErr } -var errNotMyTurn = errors.New("not my turn") - -func (r *Rollup) checkSubmitterTurn() error { - // If we are in priority rollup mode or rotator is not configured, always allow processing. - if r.cfg.PriorityRollup || r.rotator == nil { - return nil - } - - activeSubmitter, submitterIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if err != nil { - return fmt.Errorf("rollup: get current submitter err, %w", err) - } - - myAddress := r.WalletAddr().Hex() - activeAddress := activeSubmitter.Hex() - isMyTurn := activeAddress == myAddress - - // Calculate rotation timing information - if r.rotator.startTime == nil || r.rotator.epoch == nil { - log.Warn("rotator state not initialized, skipping submitter turn check", - "has_rotator", r.rotator != nil) - return errNotMyTurn - } - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - timeLeft := end - time.Now().Unix() - - // Format timestamps for human readability - startTimeFormatted := utils.FormatTime(big.NewInt(start)) - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - if !isMyTurn { - log.Debug("Not active submitter", - "active_submitter", activeAddress, - "index", submitterIndex, - "my_address", myAddress, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return errNotMyTurn - } - - log.Info("Active submitter status", - "index", submitterIndex, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "rotation_start", startTimeFormatted, - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return nil -} - // Handle chain reorganization (metrics + pending pool; DetectReorg only detects and updates block history). func (r *Rollup) handleReorg(depth uint64) error { r.metrics.SetReorgDepth(float64(depth)) @@ -519,7 +430,7 @@ func (r *Rollup) updateFeeMetrics(tx *ethtypes.Transaction, receipt *ethtypes.Re txFeeFloat, _ := txFeeEth.Float64() // Update metrics based on transaction type - if constants.IsCommitLikeMethod(method) { + if constants.IsOwnedCommitMethod(method) { r.rollupFeeSum += txFeeFloat r.metrics.RollupCostSum.Add(txFeeFloat) r.metrics.RollupCost.Set(txFeeFloat) @@ -581,8 +492,11 @@ func (r *Rollup) getTxStatus(tx *ethtypes.Transaction) (*txStatus, error) { func (r *Rollup) handlePendingTx(txRecord *types.TxRecord, tx *ethtypes.Transaction, method string) error { // Obsolete / doomed txs: cancel before timeout handling so we do not resubmit a tx that will revert. - if constants.IsCommitLikeMethod(method) { - batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 + if constants.IsOwnedCommitMethod(method) { + batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) + if err != nil { + return fmt.Errorf("parse owned commit batch index: %w", err) + } lastCommitted, err := r.Rollup.LastCommittedBatchIndex(nil) if err != nil { return fmt.Errorf("get last committed batch index error: %w", err) @@ -772,8 +686,11 @@ func (r *Rollup) handleConfirmedTx(txRecord *types.TxRecord, tx *ethtypes.Transa method := utils.ParseMethod(tx, r.abi) if status.receipt.Status == ethtypes.ReceiptStatusFailed { - if constants.IsCommitLikeMethod(method) { - batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 + if constants.IsOwnedCommitMethod(method) { + batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) + if err != nil { + return fmt.Errorf("parse owned commit batch index: %w", err) + } lastCommitted, err := r.Rollup.LastCommittedBatchIndex(nil) if err != nil { return fmt.Errorf("get last committed batch index error: %w", err) @@ -802,8 +719,11 @@ func (r *Rollup) handleConfirmedTx(txRecord *types.TxRecord, tx *ethtypes.Transa } } } else { // Transaction succeeded - if constants.IsCommitLikeMethod(method) { - batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 + if constants.IsOwnedCommitMethod(method) { + batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) + if err != nil { + return fmt.Errorf("parse owned commit batch index: %w", err) + } log.Info("Successfully committed batch", "method", method, "batch_index", batchIndex, "tx_hash", tx.Hash().String(), "block_number", status.receipt.BlockNumber.Uint64(), "gas_used", status.receipt.GasUsed, "confirm", confirmations) } else if method == constants.MethodFinalizeBatch { batchIndex := utils.ParseFBatchIndex(tx.Data()) @@ -993,84 +913,6 @@ func (r *Rollup) finalize() error { } func (r *Rollup) rollup() error { - // Get current block height - if !r.cfg.PriorityRollup { - activeSubmitter, activeIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if err != nil { - return fmt.Errorf("rollup: get current submitter err, %w", err) - } - - err = r.eventInfoStorage.Load() - if err != nil { - return fmt.Errorf("failed to load storage in rollup: %w", err) - } - log.Debug("Indexer status", - "blocks_processed", r.eventInfoStorage.BlockProcessed(), - "last_event_time", r.eventInfoStorage.BlockTime()) - - // get current block number - blockNumber, err := r.L1Client.BlockNumber(context.Background()) - if err != nil { - return fmt.Errorf("failed to get block number in rollup: %w", err) - } - // set metrics - r.metrics.SetIndexerBlockProcessed(r.eventInfoStorage.BlockProcessed()) - // check if indexed block number is too old - if blockNumber > r.eventInfoStorage.BlockProcessed()+100 { - log.Info("Indexer sync required", - "module", r.GetModuleName(), - "current_block", blockNumber, - "processed_block", r.eventInfoStorage.BlockProcessed(), - "blocks_behind", blockNumber-r.eventInfoStorage.BlockProcessed()) - return nil - } - - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - - // Calculate time remaining in current turn - timeLeft := end - time.Now().Unix() - myAddress := r.WalletAddr().Hex() - activeAddress := activeSubmitter.Hex() - isMyTurn := activeAddress == myAddress - totalSubmitters := len(r.rotator.GetSubmitterSet()) - - // Format timestamps for human readability - startTimeFormatted := utils.FormatTime(big.NewInt(start)) - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - log.Info("Rotation status", - "submitter_index", activeIndex, - "active_submitter", activeAddress, - "my_address", myAddress, - "total_submitters", totalSubmitters, - "is_my_turn", isMyTurn, - "rotation_start", startTimeFormatted, - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - - if isMyTurn { - if timeLeft < r.cfg.RotatorBuffer { - bufferFormatted := fmt.Sprintf("%dm%ds", r.cfg.RotatorBuffer/60, r.cfg.RotatorBuffer%60) - log.Info("Insufficient time for rollup", - "time_remaining", timeLeftFormatted, - "buffer_required", bufferFormatted) - return nil - } - - log.Info("Starting rollup", - "submitter_index", activeIndex, - "total_submitters", totalSubmitters) - } else { - log.Info("Skipping rollup - not active submitter", - "active_index", activeIndex, - "active_submitter", activeAddress) - return nil - } - } - if pendingN := r.pendingTxs.Len(); pendingN > int(r.cfg.MaxTxsInPendingPool) { log.Info("Pending pool full", "current_size", pendingN, @@ -1115,10 +957,6 @@ func (r *Rollup) rollup() error { return nil } - signature, err := r.buildSignatureInput(rpcRollupBatch) - if err != nil { - return err - } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -1129,33 +967,15 @@ func (r *Rollup) rollup() error { WithdrawalRoot: rpcRollupBatch.WithdrawRoot, } - storedBlobHash, err := r.Rollup.BatchBlobVersionedHashes(nil, big.NewInt(int64(batchIndex))) - if err != nil { - return fmt.Errorf("get batch blob versioned hash: %w", err) - } - useCommitState := storedBlobHash != [32]byte{} - if useCommitState { - if err := r.validateStoredBlobAgainstSealedHeader(storedBlobHash, batchIndex); err != nil { - return err - } - log.Info("Using commitState (L1 stored blob hash matches sealed header)", - "batch_index", batchIndex, - "stored_blob_hash", common.Hash(storedBlobHash).Hex()) - } - // tip and cap tip, gasFeeCap, blobFee, head, err := r.GetGasTipAndCap() if err != nil { return fmt.Errorf("get gas tip and cap error:%v", err) } - // calldata encode — commitState reuses stored blob hash and must not carry blob data in tx - var calldata []byte - if useCommitState { - calldata, err = r.abi.Pack("commitState", rollupBatch, *signature) - } else { - calldata, err = r.abi.Pack("commitBatch", rollupBatch, *signature) - } + // The official writer has one post-cutover path: the current commitBatch + // selector with a freshly constructed blob sidecar. + calldata, err := r.abi.Pack("commitBatch", rollupBatch) if err != nil { return fmt.Errorf("pack calldata error:%v", err) } @@ -1164,10 +984,11 @@ func (r *Rollup) rollup() error { // is available during eth_estimateGas simulation. var estimateBlobHashes []common.Hash var estimateBlobFeeCap *big.Int - if !useCommitState && len(rpcRollupBatch.Sidecar.Blobs) > 0 { - estimateBlobHashes = blob.BlobHashes(rpcRollupBatch.Sidecar.Blobs, rpcRollupBatch.Sidecar.Commitments) - estimateBlobFeeCap = blobFee + if len(rpcRollupBatch.Sidecar.Blobs) == 0 { + return fmt.Errorf("batch %d has no fresh blob sidecar", batchIndex) } + estimateBlobHashes = blob.BlobHashes(rpcRollupBatch.Sidecar.Blobs, rpcRollupBatch.Sidecar.Commitments) + estimateBlobFeeCap = blobFee gas, err := r.EstimateGas(r.WalletAddr(), r.rollupAddr, calldata, gasFeeCap, tip, estimateBlobHashes, estimateBlobFeeCap) if err != nil { log.Warn("Estimate gas failed", "batch_index", batchIndex, "error", err) @@ -1193,13 +1014,7 @@ func (r *Rollup) rollup() error { return fmt.Errorf("failed to get next nonce") } - // Create and sign transaction (commitState is always type-2, never blob) - var tx *ethtypes.Transaction - if useCommitState { - tx, err = r.createDynamicFeeTx(nonce, gas, tip, gasFeeCap, calldata) - } else { - tx, err = r.createRollupTx(rpcRollupBatch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) - } + tx, err := r.createRollupTx(rpcRollupBatch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) if err != nil { return fmt.Errorf("failed to create rollup tx: %w", err) } @@ -1242,10 +1057,10 @@ func (r *Rollup) getNextNonce() uint64 { } func (r *Rollup) createRollupTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) { - if len(batch.Sidecar.Blobs) > 0 { - return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) + if batch == nil || len(batch.Sidecar.Blobs) == 0 { + return nil, errors.New("official commitBatch requires a fresh blob sidecar") } - return r.createDynamicFeeTx(nonce, gas, tip, gasFeeCap, calldata) + return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) } func (r *Rollup) createBlobTx(rpcBatch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) { @@ -1287,72 +1102,20 @@ func (r *Rollup) createBlobTx(rpcBatch *eth.RPCRollupBatch, nonce, gas uint64, t }), nil } -func (r *Rollup) createDynamicFeeTx(nonce, gas uint64, tip, gasFeeCap *big.Int, calldata []byte) (*ethtypes.Transaction, error) { - return ethtypes.NewTx(ðtypes.DynamicFeeTx{ - ChainID: r.chainId, - Nonce: nonce, - GasTipCap: tip, - GasFeeCap: gasFeeCap, - Gas: gas, - To: &r.rollupAddr, - Data: calldata, - }), nil -} - -// validateStoredBlobAgainstSealedHeader requires L1 stored blob hash to match the sealed -// header blob field (offset 57). Sealed headers always carry a non-zero semantic value -// (e.g. EmptyVersionedHash); callers must not skip validation when the field decodes to zero. -func (r *Rollup) validateStoredBlobAgainstSealedHeader(stored [32]byte, batchIndex uint64) error { - if stored == ([32]byte{}) { - return nil - } - if !r.cfg.SealBatch || r.batchCache == nil { - return nil - } - header, ok := r.batchCache.GetSealedBatchHeader(batchIndex) - if !ok || header == nil { - return fmt.Errorf("commitState: sealed batch header %d not in cache", batchIndex) - } - headerBlob, err := header.BlobCommitHash() - if err != nil { - return fmt.Errorf("commitState: batch %d header blob field: %w", batchIndex, err) - } - if common.Hash(stored) != headerBlob { - return fmt.Errorf( - "commitState: L1 stored blob hash %s != sealed header %s (batch %d)", - common.Hash(stored).Hex(), headerBlob.Hex(), batchIndex, - ) - } - return nil -} - -// tryRebuildRollupCommitTx aligns an in-flight commit-like tx with L1 blob-hash state: -// - stored blob versioned hash set -> must use commitState (no blob), upgrading commitBatch / blob txs -// - stored hash cleared -> must use commitBatch (+ blob sidecar when present), downgrading stale commitState -// -// Returns handled=true when newTx must be used and the default ReSubmitTx copy path must be skipped. +// tryRebuildRollupCommitTx rebuilds an owned current commitBatch from the local +// batch cache. It deliberately ignores the old transaction's blob hash/sidecar +// and L1 stored-hash state, and always constructs a fresh blob sidecar. func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeCap, blobFeeCap *big.Int, head *ethtypes.Header) (newTx *ethtypes.Transaction, handled bool, err error) { - method := utils.ParseMethod(tx, r.abi) - if !constants.IsCommitLikeMethod(method) { + if tx.To() == nil || *tx.To() != r.rollupAddr { return nil, false, nil } - batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 - stored, err := r.Rollup.BatchBlobVersionedHashes(nil, big.NewInt(int64(batchIndex))) - if err != nil { - return nil, false, err + batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) + if errors.Is(err, utils.ErrNotOwnedCommit) { + return nil, false, nil } - if err := r.validateStoredBlobAgainstSealedHeader(stored, batchIndex); err != nil { + if err != nil { return nil, true, err } - if stored != ([32]byte{}) { - if method == constants.MethodCommitState && tx.Type() == ethtypes.DynamicFeeTxType { - return nil, false, nil - } - } else { - if method == constants.MethodCommitBatch { - return nil, false, nil - } - } var rpcRollupBatch *eth.RPCRollupBatch exist := true @@ -1364,10 +1127,6 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC if err != nil || !exist || rpcRollupBatch == nil { return nil, true, fmt.Errorf("cannot rebuild rollup commit tx: batch %d not in cache (err=%v)", batchIndex, err) } - signature, err := r.buildSignatureInput(rpcRollupBatch) - if err != nil { - return nil, true, err - } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -1378,23 +1137,7 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC WithdrawalRoot: rpcRollupBatch.WithdrawRoot, } - if stored != ([32]byte{}) { - calldata, err := r.abi.Pack("commitState", rollupBatch, *signature) - if err != nil { - return nil, true, err - } - newTx, err = r.createDynamicFeeTx(tx.Nonce(), tx.Gas(), tip, gasFeeCap, calldata) - if err != nil { - return nil, true, err - } - log.Info("Rebuilt pending rollup tx as commitState (stored blob hash on L1)", - "batch_index", batchIndex, - "old_tx_type", tx.Type(), - "old_method", method) - return newTx, true, nil - } - - calldata, err := r.abi.Pack("commitBatch", rollupBatch, *signature) + calldata, err := r.abi.Pack("commitBatch", rollupBatch) if err != nil { return nil, true, err } @@ -1405,10 +1148,9 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC if err != nil { return nil, true, err } - log.Info("Rebuilt pending rollup tx as commitBatch (no stored blob hash on L1)", + log.Info("Rebuilt pending rollup tx as fresh-blob commitBatch", "batch_index", batchIndex, - "old_tx_type", tx.Type(), - "old_method", method) + "old_tx_type", tx.Type()) return newTx, true, nil } @@ -1428,15 +1170,6 @@ func (r *Rollup) logTxInfo(tx *ethtypes.Transaction, batchIndex uint64) { ) } -func (r *Rollup) buildSignatureInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { - sigData := bindings.IRollupBatchSignatureInput{ - SignedSequencersBitmap: common.Big0, - SequencerSets: batch.CurrentSequencerSetBytes, - Signature: []byte("0x"), - } - return &sigData, nil -} - func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Header, error) { head, err := r.L1Client.HeaderByNumber(context.Background(), nil) if err != nil { @@ -1498,35 +1231,12 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Head // PreCheck is run before the submitter to check whether the submitter can be started func (r *Rollup) PreCheck() error { - - // debug stakers - stakers, err := r.Staking.GetStakers(nil) - if err != nil { - log.Debug("get stakers error", "err", err) - } else { - log.Debug("stakers", "len", len(stakers)) - for _, s := range stakers { - log.Debug("staker", "addr", s.Hex()) - } - } - // debug active stakers - activeStakers, err := r.Staking.GetActiveStakers(nil) - if err != nil { - log.Debug("get active stakers error", "err", err) - } else { - log.Debug("active stakers", "len", len(activeStakers)) - for _, s := range activeStakers { - log.Debug("active staker", "addr", s.Hex()) - } - } - - isStaker, err := r.IsStaker() + isActive, err := r.IsActive() if err != nil { - return fmt.Errorf("check if this account is sequencer error:%v", err) + return fmt.Errorf("check submitter qualification: %w", err) } - - if !isStaker { - return fmt.Errorf("this account is not staker, can not rollup") + if !isActive { + return fmt.Errorf("submitter %s is not active", r.WalletAddr().Hex()) } return nil @@ -1552,7 +1262,7 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll log.Warn("failed to get batch", "error", err) continue } - if batch != nil && len(batch.Signatures) > 0 { + if batch != nil { return batch, nil } } @@ -1560,100 +1270,6 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll return nil, nil } -// query sequencer set from sequencer contract on l2 -func QuerySequencerSet(addr common.Address, clients []iface.L2Client) ([]common.Address, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query sequencer set") - } - for _, client := range clients { - // l2 sequencer - l2Seqencer, err := bindings.NewSequencer(addr, client) - if err != nil { - log.Warn("failed to connect to sequencer", "error", err) - continue - } - // get sequencer set - seqSet, err := l2Seqencer.GetSequencerSet2(nil) - if err != nil { - log.Warn("failed to get sequencer set", "error", err) - continue - } - return seqSet, nil - } - return nil, fmt.Errorf("no sequencer set found after querying all clients") -} - -// query epoch from gov contract on l2 -func GetEpoch(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query epoch") - } - for _, client := range clients { - // l2 gov - l2Gov, err := bindings.NewGov(addr, client) - if err != nil { - log.Warn("failed to connect to gov", "error", err) - continue - } - // get epoch - epoch, err := l2Gov.RollupEpoch(nil) - if err != nil { - log.Warn("failed to get epoch", "error", err) - continue - } - return epoch, nil - } - return nil, fmt.Errorf("no epoch found after querying all clients") -} - -// query sequencer set update time from sequencer contract on l2 -func GetSequencerSetUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query sequencer set update time") - } - for _, client := range clients { - // l2 sequencer - l2Seqencer, err := bindings.NewSequencer(addr, client) - if err != nil { - log.Warn("failed to connect to sequencer", "error", err) - continue - } - // get sequencer set update time - updateTime, err := l2Seqencer.UpdateTime(nil) - if err != nil { - log.Warn("failed to get sequencer set update time", "error", err) - continue - } - return updateTime, nil - } - return nil, fmt.Errorf("no sequencer set update time found after querying all clients") -} - -// query epoch update time from gov contract on l2 -func GetEpochUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query epoch update time") - } - for _, client := range clients { - // l2 gov - l2Gov, err := bindings.NewGov(addr, client) - if err != nil { - log.Warn("failed to connect to gov", "error", err) - continue - } - // get epoch update time - updateTime, err := l2Gov.RollupEpochUpdateTime(nil) - if err != nil { - log.Warn("failed to get epoch update time", "error", err) - continue - } - return updateTime, nil - - } - return nil, fmt.Errorf("no epoch update time found after querying all clients") - -} - func UpdateGasLimit(tx *ethtypes.Transaction) (*ethtypes.Transaction, error) { // add buffer to gas limit (*1.2) newGasLimit := tx.Gas() * 12 / 10 @@ -1826,6 +1442,9 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr } else if err != nil { return nil, err } else { + if len(tx.Data()) != 0 && tx.To() != nil && *tx.To() == r.rollupAddr && utils.ParseMethod(tx, r.abi) != constants.MethodFinalizeBatch { + return nil, fmt.Errorf("refuse to resubmit non-owned rollup calldata (selector 0x%x)", tx.Data()[:min(4, len(tx.Data()))]) + } switch tx.Type() { case ethtypes.DynamicFeeTxType: newTx = ethtypes.NewTx(ðtypes.DynamicFeeTx{ @@ -1870,8 +1489,8 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr } } - // Original tx was not a blob tx, but rebuild (e.g. commitState -> commitBatch) may produce a blob tx. - // In that case blobFeeCap was never bumped above (bump only ran for BlobTxType). Apply the same bump as for blob replacements. + // A malformed/non-blob owned record cannot pass strict journal recovery, but + // keep replacement robust if one is injected into memory by a test/tool. if !resend && newTx != nil && newTx.Type() == ethtypes.BlobTxType && tx.Type() != ethtypes.BlobTxType { embeddedCap := newTx.BlobGasFeeCap() if embeddedCap != nil { @@ -1928,13 +1547,12 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr return newTx, nil } -func (r *Rollup) IsStaker() (bool, error) { - - isStaker, err := r.Staking.IsStaker(nil, r.WalletAddr()) +func (r *Rollup) IsActive() (bool, error) { + isActive, err := r.Submitter.IsActive(nil, r.WalletAddr()) if err != nil { - return false, fmt.Errorf("call IsStaker err :%v", err) + return false, fmt.Errorf("call Submitter.isActive: %w", err) } - return isStaker, nil + return isActive, nil } func (r *Rollup) EstimateGas( diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index 2c3bb3ed3..644a5d631 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -2,11 +2,11 @@ package services import ( "context" + "errors" "math/big" "testing" "time" - "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core" ethtypes "github.com/morph-l2/go-ethereum/core/types" @@ -14,7 +14,8 @@ import ( "github.com/stretchr/testify/require" "morph-l2/bindings/bindings" - "morph-l2/tx-submitter/event" + commonbatch "morph-l2/common/batch" + "morph-l2/tx-submitter/db" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/metrics" "morph-l2/tx-submitter/mock" @@ -42,47 +43,17 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie metrics.UnregisterMetrics() }) - // Create mock event storage - eventStorage := mock.NewMockEventInfoStorage() - err = eventStorage.Load() - require.NoError(t, err) - - // Initialize event storage with test data - eventStorage.SetBlockProcessed(1000) - eventStorage.SetBlockTime(uint64(time.Now().Unix())) - err = eventStorage.Store() - require.NoError(t, err) - - // Create mock event indexer - indexer := event.NewEventIndexer( - nil, // We don't need a real ethclient.Client for testing - big.NewInt(0), - ethereum.FilterQuery{}, - 100, - eventStorage, - ) - - // Create mock rotator - rotator := NewRotator(common.Address{}, common.Address{}, indexer) - - // Create mock L1Staking - l1Staking := mock.NewMockL1Staking() - // Set some test stakers - testStakers := []common.Address{ - common.HexToAddress("0x1111111111111111111111111111111111111111"), - common.HexToAddress("0x2222222222222222222222222222222222222222"), - } - l1Staking.SetActiveStakers(testStakers) + submitter := mock.NewMockSubmitter() // Create rollup config defaultCfg := utils.Config{ - MaxTip: 10e9, - MaxBaseFee: 100e9, - MinTip: 1e9, - TipFeeBump: 100, - TxTimeout: 10 * time.Second, - PriorityRollup: true, - MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) + MaxTip: 10e9, + MaxBaseFee: 100e9, + MinTip: 1e9, + TipFeeBump: 100, + TxTimeout: 10 * time.Second, + BatchBlockInterval: 1, + MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) } // Create mock journal @@ -104,17 +75,15 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie l1Mock, []iface.L2Client{l2Mock}, mockRollup, - l1Staking, + submitter, big.NewInt(1), privateKey, common.Address{}, rollupAbi, defaultCfg, nil, - rotator, nil, nil, - eventStorage, nil, ) @@ -129,6 +98,42 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie return rollup, l1Mock, l2Mock, mockRollup } +func TestPreCheckUsesSubmitterIsActive(t *testing.T) { + r, _, _, _ := setupTestRollup(t) + submitter := r.Submitter.(*mock.MockSubmitter) + + require.NoError(t, r.PreCheck()) + require.Equal(t, r.WalletAddr(), submitter.LastQuery()) + + submitter.SetActive(r.WalletAddr(), false) + require.ErrorContains(t, r.PreCheck(), "is not active") +} + +func TestRollbackCanonicalBootstrapClearsCheckpoint(t *testing.T) { + ldb, err := db.New(t.TempDir()) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, ldb.Close()) }) + require.NoError(t, ldb.PutBytes([]byte(commonbatch.SealedBatchIndicesKey), []byte("corrupt-checkpoint"))) + + cache := commonbatch.NewBatchCache( + nil, + nil, + 1, + commonbatch.BatchConfig{BlockInterval: 1}, + nil, + &iface.L2Clients{}, + nil, + nil, + ldb, + ) + r := &Rollup{batchCache: cache} + cause := errors.New("safe head changed") + err = r.rollbackCanonicalBootstrap("assemble downtime L2 blocks", cause) + require.ErrorIs(t, err, cause) + _, err = ldb.GetBytes([]byte(commonbatch.SealedBatchIndicesKey)) + require.Error(t, err, "failed startup must not leave a resumable checkpoint") +} + // TestHandleDiscardedTx tests the handling of discarded transactions func TestHandleDiscardedTx(t *testing.T) { r, l1Mock, _, _ := setupTestRollup(t) diff --git a/tx-submitter/services/rollup_test.go b/tx-submitter/services/rollup_test.go index 79fe4fcd3..664f2de5b 100644 --- a/tx-submitter/services/rollup_test.go +++ b/tx-submitter/services/rollup_test.go @@ -8,6 +8,7 @@ import ( "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto/kzg4844" + "github.com/morph-l2/go-ethereum/eth" "github.com/stretchr/testify/require" "morph-l2/tx-submitter/utils" @@ -104,6 +105,7 @@ func TestGetGasTipAndCap(t *testing.T) { } func TestReSubmitTx(t *testing.T) { + genericTo := common.HexToAddress("0x0000000000000000000000000000000000000001") marketTip := big.NewInt(3e9) // 3 Gwei market tip baseFee := big.NewInt(2e9) // 2 Gwei base fee block := types.NewBlockWithHeader( @@ -131,7 +133,7 @@ func TestReSubmitTx(t *testing.T) { GasTipCap: big.NewInt(2e9), // 2 Gwei GasFeeCap: big.NewInt(10e9), // 10 Gwei Gas: 100000, - To: &common.Address{}, + To: &genericTo, Value: big.NewInt(0), Data: []byte{1, 2, 3, 4}, }) @@ -188,7 +190,7 @@ func TestReSubmitTx(t *testing.T) { GasTipCap: uint256.MustFromBig(big.NewInt(2e9)), GasFeeCap: uint256.MustFromBig(big.NewInt(10e9)), Gas: 200000, - To: common.Address{}, + To: genericTo, Value: uint256.NewInt(0), Data: []byte{1, 2, 3, 4}, BlobFeeCap: uint256.MustFromBig(big.NewInt(5e9)), @@ -376,7 +378,6 @@ func TestTxStateTransition(t *testing.T) { // Create rollup instance rollup, l1Mock, _, _ := setupTestRollup(t) - rollup.cfg.PriorityRollup = true // Test transaction state transitions t.Run("Transaction State Flow", func(t *testing.T) { @@ -416,3 +417,32 @@ func TestTxStateTransition(t *testing.T) { require.Nil(t, txRecord) }) } + +func TestCreateRollupTxRequiresFreshBlobSidecar(t *testing.T) { + r, _, _, _ := setupTestRollup(t) + _, err := r.createRollupTx( + ð.RPCRollupBatch{}, + 1, + 100_000, + big.NewInt(1), + big.NewInt(2), + big.NewInt(1), + []byte{0x41, 0xf7, 0x56, 0xda}, + &types.Header{}, + ) + require.ErrorContains(t, err, "fresh blob sidecar") +} + +func TestReSubmitTxRejectsNonOwnedRollupCalldata(t *testing.T) { + r, l1Mock, _, _ := setupTestRollup(t) + l1Mock.Block = types.NewBlockWithHeader(&types.Header{BaseFee: big.NewInt(1)}) + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: big.NewInt(1), + GasTipCap: big.NewInt(1), + GasFeeCap: big.NewInt(2), + To: &r.rollupAddr, + Data: []byte{0xde, 0xad, 0xbe, 0xef}, + }) + _, err := r.ReSubmitTx(false, tx) + require.ErrorContains(t, err, "refuse to resubmit non-owned rollup calldata") +} diff --git a/tx-submitter/services/rotator.go b/tx-submitter/services/rotator.go deleted file mode 100644 index bb5bb81af..000000000 --- a/tx-submitter/services/rotator.go +++ /dev/null @@ -1,158 +0,0 @@ -package services - -import ( - "errors" - "fmt" - "math/big" - "sync" - "time" - - "morph-l2/tx-submitter/event" - "morph-l2/tx-submitter/iface" - "morph-l2/tx-submitter/utils" - - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/log" -) - -type Rotator struct { - // used to record the start time of rotation - // updated when the sequencerSet, stakingSet or epoch is updated - startTime *big.Int // timestamp - submitterSet []common.Address - sequencerSet []common.Address - epoch *big.Int // epoch for rotation - mu sync.Mutex // lock - l2SequencerAddr common.Address - l2GovAddr common.Address - indexer *event.EventIndexer -} - -func NewRotator(l2SeqencerAddr, l2GovAddr common.Address, indexer *event.EventIndexer) *Rotator { - return &Rotator{ - l2SequencerAddr: l2SeqencerAddr, - l2GovAddr: l2GovAddr, - indexer: indexer, - } -} - -func (r *Rotator) StartEventIndexer() { - go r.indexer.Index() -} - -// UpdateState updates the state of the rotator -// updated by event listener in the future -func (r *Rotator) UpdateState(clients []iface.L2Client, l1Staking iface.IL1Staking) error { - - epochUpdateTime, err := GetEpochUpdateTime(r.l2GovAddr, clients) - if err != nil { - log.Error("failed to get epoch update time", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to get epoch update time: %w", err) - } - // sequencer set update time - sequcerUpdateTime, err := GetSequencerSetUpdateTime(r.l2SequencerAddr, clients) - if err != nil { - log.Error("failed to get sequencer set update time", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to get sequencer set update time: %w", err) - } - - storage := r.indexer.GetStorage() - err = storage.Load() - if err != nil { - log.Error("failed to load storage", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to load storage: %w", err) - } - // if index not complete - if storage.BlockProcessed() == 0 { - return errors.New("wait event index service to complete") - } - - r.startTime = utils.MaxOfThreeBig(epochUpdateTime, sequcerUpdateTime, big.NewInt(int64(storage.BlockTime()))) - - // get current sequencer set - seqSet, err := QuerySequencerSet(r.l2SequencerAddr, clients) - if err != nil { - log.Error("failed to get sequencer set", "err", err) - return fmt.Errorf("UpdateState: failed to get sequencer set: %w", err) - } - r.SetSequencerSet(seqSet) - // get current epoch - epoch, err := GetEpoch(r.l2GovAddr, clients) - if err != nil { - log.Error("failed to get epoch", "err", err) - return err - } - r.epoch = epoch - - // get l1staking active staker set - stakers, err := l1Staking.GetActiveStakers(nil) - if err != nil { - log.Error("failed to get active stakers", "err", err) - return fmt.Errorf("UpdateState: failed to get active stakers: %w", err) - } - submitterSet := utils.IntersectionOfAddresses(r.GetSequencerSet(), stakers) - r.SetSubmitterSet(submitterSet) - // rotator info - log.Info( - "rotator state updated", - "epoch", r.epoch, - "start_time", utils.FormatTime(r.startTime), - "start_timestamp", r.startTime, - "epoch_update_time", utils.FormatTime(epochUpdateTime), - "epoch_update_timestamp", epochUpdateTime, - "seq_update_time", utils.FormatTime(sequcerUpdateTime), - "seq_update_timestamp", sequcerUpdateTime, - "indexed_latest_block", storage.BlockProcessed(), - "indexed_event_time", utils.FormatTime(big.NewInt(int64(storage.BlockTime()))), - "indexed_event_timestamp", storage.BlockTime(), - ) - - return nil -} - -// GetCurrentSubmitter returns the current sequencer that should be submitting -func (r *Rotator) CurrentSubmitter(clients []iface.L2Client, l1Staking iface.IL1Staking) (*common.Address, int64, error) { - - err := r.UpdateState(clients, l1Staking) - if err != nil { - return nil, 0, fmt.Errorf("update state err: %w", err) - } - - if len(r.GetSubmitterSet()) == 0 { - return nil, 0, fmt.Errorf("GetCurrentSubmitter: sequencer set is empty") - } - - if r.epoch.Int64() == 0 { - return nil, 0, fmt.Errorf("GetCurrentSubmitter: epoch is 0") - } - - sec := time.Now().Unix() - r.startTime.Int64() - seqIdx := sec / r.epoch.Int64() % int64(len(r.GetSequencerSet())) - - return &r.GetSubmitterSet()[seqIdx], seqIdx, nil - -} - -func (r *Rotator) SetSubmitterSet(newSet []common.Address) { - r.mu.Lock() - defer r.mu.Unlock() - r.submitterSet = newSet -} -func (r *Rotator) GetSubmitterSet() []common.Address { - r.mu.Lock() - defer r.mu.Unlock() - return r.submitterSet -} - -func (r *Rotator) SetSequencerSet(newSet []common.Address) { - r.mu.Lock() - defer r.mu.Unlock() - r.sequencerSet = newSet -} - -func (r *Rotator) GetSequencerSet() []common.Address { - r.mu.Lock() - defer r.mu.Unlock() - return r.sequencerSet - -} diff --git a/tx-submitter/types/batch_cache.go b/tx-submitter/types/batch_cache.go index 7ebe49b81..fd1cbe5c0 100644 --- a/tx-submitter/types/batch_cache.go +++ b/tx-submitter/types/batch_cache.go @@ -45,21 +45,12 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { return nil, false } - // Validate batch before caching - batch must exist and have signatures - if fetchedBatch != nil && len(fetchedBatch.Signatures) > 0 { - // Store valid batch in cache for future use + if fetchedBatch != nil { b.m.Lock() b.batchCache[batchIndex] = fetchedBatch b.m.Unlock() return fetchedBatch, true - } else if fetchedBatch != nil { - // Batch exists but doesn't have signatures, don't cache it - log.Debug("Batch validation failed - no signatures", - "batch_index", batchIndex, - "found", fetchedBatch != nil, - "has_signatures", len(fetchedBatch.Signatures) > 0) - return fetchedBatch, true } } @@ -67,12 +58,8 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { } func (b *BatchCacheLegacy) Set(batchIndex uint64, batch *eth.RPCRollupBatch) { - // Validate batch before caching - batch must exist and have signatures - if batch == nil || len(batch.Signatures) == 0 { - log.Debug("Refusing to cache invalid batch", - "batch_index", batchIndex, - "exists", batch != nil, - "has_signatures", batch != nil && len(batch.Signatures) > 0) + if batch == nil { + log.Debug("Refusing to cache nil batch", "batch_index", batchIndex) return } diff --git a/tx-submitter/utils/config.go b/tx-submitter/utils/config.go index 4e9269f95..3a1520636 100644 --- a/tx-submitter/utils/config.go +++ b/tx-submitter/utils/config.go @@ -1,10 +1,13 @@ package utils import ( + "encoding/json" + "fmt" "time" "github.com/urfave/cli" + "morph-l2/common/batch" "morph-l2/tx-submitter/flags" ) @@ -28,8 +31,13 @@ type Config struct { // RollupAddress is the Rollup contract address. RollupAddress string - // StakingAddress - L1StakingAddress string + // SubmitterAddress is the Submitter qualification and stake contract. + SubmitterAddress string + + // Static batch sealing configuration. Values are snapshotted before cutover + // and must remain identical across the working and standby instances. + BatchBlockInterval uint64 + BatchTimeout uint64 // PollInterval is the delay between querying L2 for more transaction // and creating a new batch. @@ -46,18 +54,11 @@ type Config struct { // finalize // if start finalize Finalize bool - // L2 contract - L2SequencerAddress string - L2GovAddress string - // metrics MetricsServerEnable bool MetricsHostname string MetricsPort uint64 - // decentralized - PriorityRollup bool - // tx fee limit TxFeeLimit uint64 @@ -82,6 +83,10 @@ type Config struct { // journal file path JournalFilePath string + // BatchConfigPreflight prints the effective static batch configuration and exits. + BatchConfigPreflight bool + BatchConfigSourceBlockNumber uint64 + BatchConfigSourceBlockHash string // tip bump TipFeeBump uint64 MaxTip uint64 @@ -99,14 +104,6 @@ type Config struct { ExternalSignRsaPriv string // rough estimate gas switch RoughEstimateGas bool - // rotator interval buffer - RotatorBuffer int64 - // listener process path - StakingEventStoreFilename string - // l1 staking deployed block number - L1StakingDeployedBlockNumber uint64 - // event indexer index step - EventIndexStep uint64 // leveldb path name LeveldbPathName string BlockNotIncreasedThreshold int64 @@ -118,6 +115,39 @@ type Config struct { BatchV2UpgradeTime uint64 } +// BatchConfig returns the immutable configuration consumed by common/batch. +func (c Config) BatchConfig() batch.BatchConfig { + return batch.BatchConfig{ + BlockInterval: c.BatchBlockInterval, + Timeout: c.BatchTimeout, + } +} + +// BatchConfigReport is the stable, machine-readable preflight output used by +// operators to compare all working and standby instances before cutover. +type BatchConfigReport struct { + BlockInterval uint64 `json:"batch_block_interval"` + Timeout uint64 `json:"batch_timeout"` + SourceBlockNumber uint64 `json:"source_block_number"` + SourceBlockHash string `json:"source_block_hash"` + Hash string `json:"config_hash"` +} + +func (c Config) BatchConfigReport() BatchConfigReport { + bc := c.BatchConfig() + return BatchConfigReport{ + BlockInterval: bc.BlockInterval, + Timeout: bc.Timeout, + SourceBlockNumber: c.BatchConfigSourceBlockNumber, + SourceBlockHash: c.BatchConfigSourceBlockHash, + Hash: bc.Hash().Hex(), + } +} + +func (c Config) BatchConfigReportJSON() ([]byte, error) { + return json.Marshal(c.BatchConfigReport()) +} + // NewConfig parses the DriverConfig from the provided flags or environment variables. // This method fails if ValidateConfig deems the configuration to be malformed. func NewConfig(ctx *cli.Context) (Config, error) { @@ -131,18 +161,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { TxTimeout: ctx.GlobalDuration(flags.TxTimeoutFlag.Name), // finalize Finalize: ctx.GlobalBool(flags.FinalizeFlag.Name), - // L1 contract - L1StakingAddress: ctx.GlobalString(flags.L1StakingAddressFlag.Name), - RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), - // L2 contract - L2SequencerAddress: ctx.GlobalString(flags.L2SequencerAddressFlag.Name), - L2GovAddress: ctx.GlobalString(flags.L2GovAddressFlag.Name), + // L1 contracts and static batch configuration + SubmitterAddress: ctx.GlobalString(flags.SubmitterAddressFlag.Name), + RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), + BatchBlockInterval: ctx.GlobalUint64(flags.BatchBlockIntervalFlag.Name), + BatchTimeout: ctx.GlobalUint64(flags.BatchTimeoutFlag.Name), // metrics MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnable.Name), MetricsHostname: ctx.GlobalString(flags.MetricsHostname.Name), MetricsPort: ctx.GlobalUint64(flags.MetricsPort.Name), - // decentralized - PriorityRollup: ctx.GlobalBool(flags.PriorityRollupFlag.Name), // tx config TxFeeLimit: ctx.GlobalUint64(flags.TxFeeLimitFlag.Name), @@ -160,12 +187,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { GasLimitBuffer: ctx.GlobalUint64(flags.GasLimitBuffer.Name), - JournalFilePath: ctx.GlobalString(flags.JournalFlag.Name), - TipFeeBump: ctx.GlobalUint64(flags.TipFeeBumpFlag.Name), - MaxTip: ctx.GlobalUint64(flags.MaxTipFlag.Name), - MinTip: ctx.GlobalUint64(flags.MinTipFlag.Name), - MaxBaseFee: ctx.GlobalUint64(flags.MaxBaseFeeFlag.Name), - MaxTxsInPendingPool: ctx.GlobalUint64(flags.MaxTxsInPendingPoolFlag.Name), + JournalFilePath: ctx.GlobalString(flags.JournalFlag.Name), + BatchConfigPreflight: ctx.GlobalBool(flags.BatchConfigPreflightFlag.Name), + BatchConfigSourceBlockNumber: ctx.GlobalUint64(flags.BatchConfigSourceBlockNumberFlag.Name), + BatchConfigSourceBlockHash: ctx.GlobalString(flags.BatchConfigSourceBlockHashFlag.Name), + TipFeeBump: ctx.GlobalUint64(flags.TipFeeBumpFlag.Name), + MaxTip: ctx.GlobalUint64(flags.MaxTipFlag.Name), + MinTip: ctx.GlobalUint64(flags.MinTipFlag.Name), + MaxBaseFee: ctx.GlobalUint64(flags.MaxBaseFeeFlag.Name), + MaxTxsInPendingPool: ctx.GlobalUint64(flags.MaxTxsInPendingPoolFlag.Name), // external sign ExternalSign: ctx.GlobalBool(flags.ExternalSign.Name), @@ -176,15 +206,6 @@ func NewConfig(ctx *cli.Context) (Config, error) { ExternalSignRsaPriv: ctx.GlobalString(flags.ExternalSignRsaPriv.Name), // rough estimate gas switch RoughEstimateGas: ctx.GlobalBool(flags.RoughEstimateGasFlag.Name), - // rotator interval buffer - RotatorBuffer: ctx.GlobalInt64(flags.RotatorBufferFlag.Name), - - // path - StakingEventStoreFilename: ctx.GlobalString(flags.StakingEventStoreFileFlag.Name), - // l1 staking deployed block number - L1StakingDeployedBlockNumber: ctx.GlobalUint64(flags.L1StakingDeployedBlocknumFlag.Name), - // index step - EventIndexStep: ctx.GlobalUint64(flags.EventIndexStepFlag.Name), // leveldb path name LeveldbPathName: ctx.GlobalString(flags.LeveldbPathNameFlag.Name), // BlockNotIncreasedThreshold @@ -197,5 +218,9 @@ func NewConfig(ctx *cli.Context) (Config, error) { BatchV2UpgradeTime: ctx.GlobalUint64(flags.BatchV2UpgradeTimeFlag.Name), } + if err := cfg.BatchConfig().Validate(); err != nil { + return Config{}, fmt.Errorf("invalid static batch configuration: %w", err) + } + return cfg, nil } diff --git a/tx-submitter/utils/config_test.go b/tx-submitter/utils/config_test.go new file mode 100644 index 000000000..08f53f76a --- /dev/null +++ b/tx-submitter/utils/config_test.go @@ -0,0 +1,40 @@ +package utils + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestConfigBatchConfig(t *testing.T) { + tests := []struct { + name string + cfg Config + wantErr bool + }{ + {name: "interval only", cfg: Config{BatchBlockInterval: 10}}, + {name: "timeout only", cfg: Config{BatchTimeout: 60}}, + {name: "both", cfg: Config{BatchBlockInterval: 10, BatchTimeout: 60}}, + {name: "both zero", cfg: Config{}, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.wantErr, tt.cfg.BatchConfig().Validate() != nil) + }) + } +} + +func TestBatchConfigReportIncludesSourceAndStableHash(t *testing.T) { + cfg := Config{ + BatchBlockInterval: 10, + BatchTimeout: 60, + BatchConfigSourceBlockNumber: 123, + BatchConfigSourceBlockHash: "0xabc", + } + report := cfg.BatchConfigReport() + require.Equal(t, uint64(10), report.BlockInterval) + require.Equal(t, uint64(60), report.Timeout) + require.Equal(t, uint64(123), report.SourceBlockNumber) + require.Equal(t, "0xabc", report.SourceBlockHash) + require.Equal(t, cfg.BatchConfig().Hash().Hex(), report.Hash) +} diff --git a/tx-submitter/utils/utils.go b/tx-submitter/utils/utils.go index 7001e5dae..2b82fe4b3 100644 --- a/tx-submitter/utils/utils.go +++ b/tx-submitter/utils/utils.go @@ -4,9 +4,9 @@ import ( "bytes" "context" "encoding/binary" + "errors" "fmt" "math/big" - "reflect" "regexp" "strconv" "time" @@ -20,6 +20,70 @@ import ( "github.com/morph-l2/go-ethereum/log" ) +var ErrNotOwnedCommit = errors.New("calldata is not an owned current commitBatch") + +// ParseOwnedCommit accepts only the current, post-cutover commitBatch selector. +// Historical commitBatch, commitState, commitBatchWithProof, and unknown +// calldata must never be imported into the official writer's pending state. +func ParseOwnedCommit(data []byte, current *abi.ABI) (methodName string, input *bindings.IRollupBatchDataInput, err error) { + if current == nil || len(data) < 4 { + return "", nil, ErrNotOwnedCommit + } + method, ok := current.Methods["commitBatch"] + if !ok || !bytes.Equal(data[:4], method.ID) { + return "", nil, ErrNotOwnedCommit + } + values, err := method.Inputs.Unpack(data[4:]) + if err != nil || len(values) != 1 { + if err == nil { + err = errors.New("unexpected commitBatch argument count") + } + return "", nil, fmt.Errorf("decode owned commitBatch: %w", err) + } + defer func() { + if recovered := recover(); recovered != nil { + methodName = "" + input = nil + err = fmt.Errorf("decode owned commitBatch tuple: %v", recovered) + } + }() + converted := abi.ConvertType(values[0], new(bindings.IRollupBatchDataInput)) + input, ok = converted.(*bindings.IRollupBatchDataInput) + if !ok || input == nil { + return "", nil, errors.New("decode owned commitBatch: invalid batch tuple") + } + return method.Name, input, nil +} + +func ParseOwnedCommitBatchIndex(data []byte, current *abi.ABI) (uint64, error) { + _, input, err := ParseOwnedCommit(data, current) + if err != nil { + return 0, err + } + if len(input.ParentBatchHeader) < 9 { + return 0, errors.New("owned commitBatch parent header is too short") + } + parentIndex := binary.BigEndian.Uint64(input.ParentBatchHeader[1:9]) + if parentIndex == ^uint64(0) { + return 0, errors.New("owned commitBatch parent index overflows") + } + return parentIndex + 1, nil +} + +// ParseParentBatchIndex is retained for non-authoritative diagnostics. It is +// strict: only the current commitBatch selector is accepted. +func ParseParentBatchIndex(data []byte) uint64 { + current, err := bindings.RollupMetaData.GetAbi() + if err != nil { + return 0 + } + batchIndex, err := ParseOwnedCommitBatchIndex(data, current) + if err != nil || batchIndex == 0 { + return 0 + } + return batchIndex - 1 +} + // Loop Run the f func periodically. func Loop(ctx context.Context, period time.Duration, f func()) { tick := time.NewTicker(period) @@ -63,50 +127,6 @@ func ParseFBatchIndex(calldata []byte) uint64 { return binary.BigEndian.Uint64(batchBytes[1:9]) } -func ParseParentBatchIndex(calldata []byte) uint64 { - /// * Field Bytes Type Index Comments - /// * version 1 uint8 0 The batch version - /// * batchIndex 8 uint64 1 The index of the batch - /// * l1MessagePopped 8 uint64 9 Number of L1 messages popped in the batch - - if len(calldata) < 4 { - return 0 - } - rollupAbi, err := bindings.RollupMetaData.GetAbi() - if err != nil { - return 0 - } - sel := calldata[:4] - var method abi.Method - var ok bool - if bytes.Equal(sel, rollupAbi.Methods["commitState"].ID) { - method, ok = rollupAbi.Methods["commitState"] - } else if bytes.Equal(sel, rollupAbi.Methods["commitBatch"].ID) { - method, ok = rollupAbi.Methods["commitBatch"] - } else { - // Unknown selector: keep legacy behavior (unpack as commitBatch). Matches older fixtures and - // any tx whose first tuple matches BatchDataInput layout even if the selector differs. - method, ok = rollupAbi.Methods["commitBatch"] - } - if !ok { - return 0 - } - parms, err := method.Inputs.UnpackValues(calldata[4:]) - if err != nil || len(parms) == 0 { - return 0 - } - v := reflect.ValueOf(parms[0]) - pbh := v.FieldByName("ParentBatchHeader") - if !pbh.IsValid() { - return 0 - } - b := pbh.Bytes() - if len(b) < 9 { - return 0 - } - return binary.BigEndian.Uint64(b[1:9]) -} - // SetFBatchIndex sets the batch index in the calldata while preserving all other data func SetFBatchIndex(calldata []byte, batchIndex uint64) error { if len(calldata) < 4 { @@ -152,18 +172,14 @@ func ParseBusinessInfo(tx *types.Transaction, a *abi.ABI) []interface{} { // var batchIndex uint64 // var finalizedIndex uint64 var res []interface{} - if len(tx.Data()) > 0 { + if len(tx.Data()) >= 4 { id := tx.Data()[:4] if bytes.Equal(id, a.Methods["commitBatch"].ID) { method := "commitBatch" - batchIndex := ParseParentBatchIndex(tx.Data()) + 1 - res = append(res, - "method", method, - "batchIndex", batchIndex, - ) - } else if bytes.Equal(id, a.Methods["commitState"].ID) { - method := "commitState" - batchIndex := ParseParentBatchIndex(tx.Data()) + 1 + batchIndex, err := ParseOwnedCommitBatchIndex(tx.Data(), a) + if err != nil { + return []interface{}{} + } res = append(res, "method", method, "batchIndex", batchIndex, @@ -195,8 +211,6 @@ func ParseMethod(tx *types.Transaction, a *abi.ABI) string { id := tx.Data()[:4] if bytes.Equal(id, a.Methods["commitBatch"].ID) { return "commitBatch" - } else if bytes.Equal(id, a.Methods["commitState"].ID) { - return "commitState" } else if bytes.Equal(id, a.Methods["finalizeBatch"].ID) { return "finalizeBatch" } else { diff --git a/tx-submitter/utils/utils_test.go b/tx-submitter/utils/utils_test.go index 75f2382f2..8b9eea4b5 100644 --- a/tx-submitter/utils/utils_test.go +++ b/tx-submitter/utils/utils_test.go @@ -8,11 +8,11 @@ import ( ) // test ParseBatchIndex -func TestParseBatchIndex(t *testing.T) { +func TestParseParentBatchIndexRejectsLegacyCalldata(t *testing.T) { calldata := "4a8d544f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000008f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e02c48c62b7604ecf508766324cd85afdc5faeb86de53f12dee5c24c7e25957b02018f517672a7760905227d4f085cf88d82b4793497846bb366b6cedd69af06aae5857a041c5a53ed68439ff4c9b8a79b9b749eb93f1e07ed07f58d60ebcf737300000000000000000000000000000000000000000000000000000000000000f900000000000000377b00000000000000000000000000001d987eb22c17eea2e2e3f3756599686586cbc42883ceedded826bc8508c13539cf6e017301c53247c7de720dd18b7d668cbcc17cb711a7aae46fbc43224203e0bca62c74b38e4c32df8e0656c3bd6acedc0ec57684327c99d10a1247f00ab8d3dece2c48c62b7604ecf508766324cd85afdc5faeb86de53f12dee5c24c7e25957b02e5857a041c5a53ed68439ff4c9b8a79b9b749eb93f1e07ed07f58d60ebcf7373a4d7461c3b8d74650efdca322d5fe15e699d534ee47ec9321bcb82bc7a9ec6e97bf7c21d9929b9d5d906a163a1dd8e74341ef11f7b84681b67d76953ee6ee3fb000000000000000000000000000000000000000000000000000000000000000000000000008ca2025800000000006acc320000000067d1c5aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc330000000067d1c5ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc340000000067d1c5ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc350000000067d1c5ad00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc360000000067d1c5ae00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc370000000067d1c5af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc380000000067d1c5b000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acc390000000067d1c5b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3a0000000067d1c5b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc3b0000000067d1c5b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3c0000000067d1c5b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3d0000000067d1c5b600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc3e0000000067d1c5b700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3f0000000067d1c5b900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc400000000067d1c5ba00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc410000000067d1c5bc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc420000000067d1c5bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc430000000067d1c5be00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc440000000067d1c5bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc450000000067d1c5c000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc460000000067d1c5c100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc470000000067d1c5c200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc480000000067d1c5c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc490000000067d1c5c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4a0000000067d1c5c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4b0000000067d1c5c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc4c0000000067d1c5c700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4d0000000067d1c5c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4e0000000067d1c5c900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc4f0000000067d1c5ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc500000000067d1c5cc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc510000000067d1c5cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc520000000067d1c5ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc530000000067d1c5cf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc540000000067d1c5d000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800005000000000000006acc550000000067d1c5d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc560000000067d1c5d200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc570000000067d1c5d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc580000000067d1c5d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc590000000067d1c5d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc5a0000000067d1c5d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5b0000000067d1c5d700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5c0000000067d1c5d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5d0000000067d1c5d900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc5e0000000067d1c5da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc5f0000000067d1c5db00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc600000000067d1c5dc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc610000000067d1c5dd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc620000000067d1c5de00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc630000000067d1c5df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc640000000067d1c5e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc650000000067d1c5e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc660000000067d1c5e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc670000000067d1c5e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc680000000067d1c5e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc690000000067d1c5e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6a0000000067d1c5e700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6b0000000067d1c5e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6c0000000067d1c5e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc6d0000000067d1c5ea00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6e0000000067d1c5eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc6f0000000067d1c5ec00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc700000000067d1c5ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc710000000067d1c5ee00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc720000000067d1c5ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc730000000067d1c5f000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc740000000067d1c5f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc750000000067d1c5f400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc760000000067d1c5f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc770000000067d1c5f600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc780000000067d1c5f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc790000000067d1c5f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7a0000000067d1c5f900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7b0000000067d1c5fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc7c0000000067d1c5fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7d0000000067d1c5fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7e0000000067d1c5fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7f0000000067d1c5ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc800000000067d1c60000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc810000000067d1c60200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc820000000067d1c60300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc830000000067d1c60400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc840000000067d1c60600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc850000000067d1c60700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc860000000067d1c60800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc870000000067d1c60a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc880000000067d1c60c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc890000000067d1c60e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8a0000000067d1c60f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc8b0000000067d1c61000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc8c0000000067d1c61200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8d0000000067d1c61300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8e0000000067d1c61400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc8f0000000067d1c61500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc900000000067d1c61600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc910000000067d1c61700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc920000000067d1c61800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc930000000067d1c61900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc940000000067d1c61a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc950000000067d1c61b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc960000000067d1c61d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc970000000067d1c61e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc980000000067d1c61f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc990000000067d1c62000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9a0000000067d1c62100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9b0000000067d1c62200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc9c0000000067d1c62300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9d0000000067d1c62500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9e0000000067d1c62600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc9f0000000067d1c62700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca00000000067d1c62800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca10000000067d1c62a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca20000000067d1c62b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca30000000067d1c62c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca40000000067d1c62d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca50000000067d1c62e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca60000000067d1c63000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca70000000067d1c63300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acca80000000067d1c63400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca90000000067d1c63600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accaa0000000067d1c63900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accab0000000067d1c63a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accac0000000067d1c63d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accad0000000067d1c63e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accae0000000067d1c63f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accaf0000000067d1c64100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb00000000067d1c64300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb10000000067d1c64500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accb20000000067d1c64700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb30000000067d1c64900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb40000000067d1c64b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb50000000067d1c64c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb60000000067d1c64e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb70000000067d1c64f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb80000000067d1c65000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb90000000067d1c65200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accba0000000067d1c65300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbb0000000067d1c65400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbc0000000067d1c65500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbd0000000067d1c65600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbe0000000067d1c65700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbf0000000067d1c65900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc00000000067d1c65a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accc10000000067d1c65b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc20000000067d1c65c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc30000000067d1c65d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc40000000067d1c65e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc50000000067d1c65f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc60000000067d1c66000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accc70000000067d1c66100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc80000000067d1c66200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc90000000067d1c66300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accca0000000067d1c66400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acccb0000000067d1c66500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acccc0000000067d1c66600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acccd0000000067d1c66700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accce0000000067d1c66800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acccf0000000067d1c66900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd00000000067d1c66a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd10000000067d1c66b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd20000000067d1c66c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd30000000067d1c66d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd40000000067d1c66e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd50000000067d1c66f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd60000000067d1c67000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd70000000067d1c67200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd80000000067d1c67300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd90000000067d1c67400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accda0000000067d1c67500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdb0000000067d1c67600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdc0000000067d1c67700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdd0000000067d1c67800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accde0000000067d1c67900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdf0000000067d1c67a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce00000000067d1c67b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce10000000067d1c67c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce20000000067d1c67d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce30000000067d1c67e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce40000000067d1c67f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce50000000067d1c68000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce60000000067d1c68100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce70000000067d1c68200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce80000000067d1c68300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce90000000067d1c68400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accea0000000067d1c68500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acceb0000000067d1c68600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accec0000000067d1c68700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acced0000000067d1c68800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accee0000000067d1c68900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accef0000000067d1c68b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf00000000067d1c68d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf10000000067d1c68e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf20000000067d1c68f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf30000000067d1c69000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accf40000000067d1c69100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf50000000067d1c69200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accf60000000067d1c69300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accf70000000067d1c69400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf80000000067d1c69500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf90000000067d1c69600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accfa0000000067d1c69700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfb0000000067d1c69800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfc0000000067d1c69900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfd0000000067d1c69a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfe0000000067d1c69b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accff0000000067d1c69c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd000000000067d1c69d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd010000000067d1c69e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd020000000067d1c69f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd030000000067d1c6a000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd040000000067d1c6a100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd050000000067d1c6a300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd060000000067d1c6a400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd070000000067d1c6a500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd080000000067d1c6a600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd090000000067d1c6a700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0a0000000067d1c6a800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd0b0000000067d1c6a900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0c0000000067d1c6aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd0d0000000067d1c6ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0e0000000067d1c6ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0f0000000067d1c6af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd100000000067d1c6b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd110000000067d1c6b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd120000000067d1c6b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd130000000067d1c6b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd140000000067d1c6b800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd150000000067d1c6bb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd160000000067d1c6bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd170000000067d1c6bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd180000000067d1c6c100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd190000000067d1c6c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1a0000000067d1c6c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1b0000000067d1c6c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1c0000000067d1c6c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1d0000000067d1c6c700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1e0000000067d1c6c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1f0000000067d1c6ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd200000000067d1c6cb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd210000000067d1c6cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd220000000067d1c6ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd230000000067d1c6cf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd240000000067d1c6d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd250000000067d1c6d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd260000000067d1c6d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd270000000067d1c6d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd280000000067d1c6d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd290000000067d1c6d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2a0000000067d1c6da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2b0000000067d1c6dc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd2c0000000067d1c6de00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2d0000000067d1c6df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2e0000000067d1c6e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2f0000000067d1c6e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd300000000067d1c6e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd310000000067d1c6e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd320000000067d1c6e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd330000000067d1c6e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd340000000067d1c6e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd350000000067d1c6e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd360000000067d1c6eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd370000000067d1c6ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd380000000067d1c6ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd390000000067d1c6f100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3a0000000067d1c6f200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3b0000000067d1c6f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3c0000000067d1c6f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3d0000000067d1c6f600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3e0000000067d1c6f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3f0000000067d1c6f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd400000000067d1c6fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd410000000067d1c6fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd420000000067d1c6fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd430000000067d1c6fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd440000000067d1c6fe00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd450000000067d1c6ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd460000000067d1c70000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd470000000067d1c70100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd480000000067d1c70200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd490000000067d1c70300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4a0000000067d1c70400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4b0000000067d1c70500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4c0000000067d1c70600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4d0000000067d1c70700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4e0000000067d1c70800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4f0000000067d1c70900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd500000000067d1c70b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd510000000067d1c70c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd520000000067d1c70d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd530000000067d1c70e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd540000000067d1c70f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd550000000067d1c71000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd560000000067d1c71100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd570000000067d1c71300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd580000000067d1c71500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd590000000067d1c71600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd5a0000000067d1c71700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5b0000000067d1c71800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd5c0000000067d1c71900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5d0000000067d1c71a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acd5e0000000067d1c71b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5f0000000067d1c71c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd600000000067d1c71d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd610000000067d1c71e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd620000000067d1c71f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd630000000067d1c72000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd640000000067d1c72100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd650000000067d1c72200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd660000000067d1c72300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd670000000067d1c72400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd680000000067d1c72500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd690000000067d1c72600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd6a0000000067d1c72700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6b0000000067d1c72800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6c0000000067d1c72900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6d0000000067d1c72a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd6e0000000067d1c72b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acd6f0000000067d1c72c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd700000000067d1c72e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd710000000067d1c72f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd720000000067d1c73000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd730000000067d1c73100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd740000000067d1c73200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd750000000067d1c73300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd760000000067d1c73400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd770000000067d1c73500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd780000000067d1c73600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd790000000067d1c73700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd7a0000000067d1c73800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd7b0000000067d1c73900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7c0000000067d1c73a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7d0000000067d1c73b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd7e0000000067d1c73c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7f0000000067d1c73e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd800000000067d1c73f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd810000000067d1c74000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd820000000067d1c74100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd830000000067d1c74200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd840000000067d1c74300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd850000000067d1c74400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd860000000067d1c74500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd870000000067d1c74600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd880000000067d1c74700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd890000000067d1c74800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8a0000000067d1c74900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd8b0000000067d1c74a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8c0000000067d1c74b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8d0000000067d1c74c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8e0000000067d1c74d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8f0000000067d1c74f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd900000000067d1c75000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd910000000067d1c75100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd920000000067d1c75200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd930000000067d1c75300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd940000000067d1c75500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd950000000067d1c75600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd960000000067d1c75700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd970000000067d1c75800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd980000000067d1c75900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd990000000067d1c75a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9a0000000067d1c75b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9b0000000067d1c75c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9c0000000067d1c75d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9d0000000067d1c75e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9e0000000067d1c75f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9f0000000067d1c76000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acda00000000067d1c76200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda10000000067d1c76300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acda20000000067d1c76500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda30000000067d1c76600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda40000000067d1c76700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda50000000067d1c76800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda60000000067d1c76a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda70000000067d1c76b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda80000000067d1c76c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda90000000067d1c76d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdaa0000000067d1c76e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdab0000000067d1c76f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdac0000000067d1c77000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdad0000000067d1c77100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdae0000000067d1c77200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdaf0000000067d1c77300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb00000000067d1c77400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb10000000067d1c77500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb20000000067d1c77600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb30000000067d1c77700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb40000000067d1c77800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb50000000067d1c77900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb60000000067d1c77a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb70000000067d1c77b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb80000000067d1c77c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb90000000067d1c77e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdba0000000067d1c78000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbb0000000067d1c78200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbc0000000067d1c78300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbd0000000067d1c78400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbe0000000067d1c78600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbf0000000067d1c78700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc00000000067d1c78800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc10000000067d1c78b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc20000000067d1c78c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc30000000067d1c78d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc40000000067d1c78f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc50000000067d1c79100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc60000000067d1c79300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc70000000067d1c79400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc80000000067d1c79500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc90000000067d1c79700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdca0000000067d1c79800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdcb0000000067d1c79900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdcc0000000067d1c79b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdcd0000000067d1c79c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdce0000000067d1c79e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdcf0000000067d1c79f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd00000000067d1c7a000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd10000000067d1c7a200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd20000000067d1c7a400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd30000000067d1c7a600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd40000000067d1c7a700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd50000000067d1c7a800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd60000000067d1c7a900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd70000000067d1c7aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd80000000067d1c7ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd90000000067d1c7ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdda0000000067d1c7ad00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acddb0000000067d1c7ae00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acddc0000000067d1c7af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acddd0000000067d1c7b000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdde0000000067d1c7b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acddf0000000067d1c7b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde00000000067d1c7b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde10000000067d1c7b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde20000000067d1c7b700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde30000000067d1c7b800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde40000000067d1c7b900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde50000000067d1c7bb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde60000000067d1c7bc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde70000000067d1c7bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde80000000067d1c7bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acde90000000067d1c7c000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdea0000000067d1c7c200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdeb0000000067d1c7c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdec0000000067d1c7c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acded0000000067d1c7c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acdee0000000067d1c7c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdef0000000067d1c7c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf00000000067d1c7c900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdf10000000067d1c7ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf20000000067d1c7cb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf30000000067d1c7cc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf40000000067d1c7cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf50000000067d1c7ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf60000000067d1c7d000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf70000000067d1c7d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf80000000067d1c7d200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf90000000067d1c7d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfa0000000067d1c7d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdfb0000000067d1c7d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfc0000000067d1c7d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfd0000000067d1c7d700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfe0000000067d1c7d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdff0000000067d1c7d900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace000000000067d1c7da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace010000000067d1c7db00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace020000000067d1c7dd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace030000000067d1c7df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace040000000067d1c7e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace050000000067d1c7e100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800005000000000000006ace060000000067d1c7e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace070000000067d1c7e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace080000000067d1c7e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace090000000067d1c7e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace0a0000000067d1c7e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0b0000000067d1c7e700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0c0000000067d1c7e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0d0000000067d1c7e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace0e0000000067d1c7ea00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0f0000000067d1c7eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace100000000067d1c7ec00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace110000000067d1c7ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace120000000067d1c7ee00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace130000000067d1c7ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace140000000067d1c7f000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace150000000067d1c7f100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace160000000067d1c7f200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace170000000067d1c7f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace180000000067d1c7f400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace190000000067d1c7f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1a0000000067d1c7f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1b0000000067d1c7f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1c0000000067d1c7f900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1d0000000067d1c7fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1e0000000067d1c7fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace1f0000000067d1c7fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace200000000067d1c7fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace210000000067d1c7fe00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace220000000067d1c7ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace230000000067d1c80000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace240000000067d1c80100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace250000000067d1c80200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace260000000067d1c80300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace270000000067d1c80400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace280000000067d1c80500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace290000000067d1c80600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2a0000000067d1c80800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2b0000000067d1c80900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2c0000000067d1c80a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2d0000000067d1c80c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2e0000000067d1c80d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2f0000000067d1c80e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace300000000067d1c81000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace310000000067d1c81100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace320000000067d1c81200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace330000000067d1c81300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace340000000067d1c81400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace350000000067d1c81500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace360000000067d1c81600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace370000000067d1c81700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace380000000067d1c81800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace390000000067d1c81900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006ace3a0000000067d1c81b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3b0000000067d1c81c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3c0000000067d1c81d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3d0000000067d1c81f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3e0000000067d1c82100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace3f0000000067d1c82300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace400000000067d1c82400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace410000000067d1c82500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace420000000067d1c82600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace430000000067d1c82700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace440000000067d1c82800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace450000000067d1c82900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace460000000067d1c82a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace470000000067d1c82b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace480000000067d1c82c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace490000000067d1c82d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace4a0000000067d1c82e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace4b0000000067d1c83000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4c0000000067d1c83100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4d0000000067d1c83200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4e0000000067d1c83400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace4f0000000067d1c83500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace500000000067d1c83600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace510000000067d1c83700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace520000000067d1c83800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace530000000067d1c83900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace540000000067d1c83a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace550000000067d1c83b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace560000000067d1c83c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace570000000067d1c83d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace580000000067d1c83e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace590000000067d1c83f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5a0000000067d1c84100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5b0000000067d1c84200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5c0000000067d1c84300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5d0000000067d1c84400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5e0000000067d1c84500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5f0000000067d1c84700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace600000000067d1c84900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace610000000067d1c84a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace620000000067d1c84b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace630000000067d1c84c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace640000000067d1c84d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace650000000067d1c84e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace660000000067d1c84f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace670000000067d1c85000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace680000000067d1c85100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace690000000067d1c85200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6a0000000067d1c85300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace6b0000000067d1c85400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace6c0000000067d1c85600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6d0000000067d1c85800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace6e0000000067d1c85900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6f0000000067d1c85a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace700000000067d1c85b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace710000000067d1c85c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace720000000067d1c85d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace730000000067d1c85e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace740000000067d1c85f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace750000000067d1c86000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace760000000067d1c86100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace770000000067d1c86300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace780000000067d1c86400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace790000000067d1c86500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7a0000000067d1c86700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7b0000000067d1c86800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7c0000000067d1c86900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7d0000000067d1c86a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7e0000000067d1c86c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7f0000000067d1c86d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace800000000067d1c86e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace810000000067d1c87000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace820000000067d1c87100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace830000000067d1c87200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace840000000067d1c87300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace850000000067d1c87400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace860000000067d1c87500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace870000000067d1c87600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace880000000067d1c87700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace890000000067d1c87800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000015f903b2fe6b812c9c5b4882525df682e2a26238bdd18badf5a4d3bf2dc2ec8acd600d92182181e25359a631da62585b00000000000000000000000000000000022a08b55fac8d2669fb3a47977ac43b2b9918d953532cab1625c9e94f49c333b7160442a38e8399a285646df4081c60" bs, err := hex.DecodeString(calldata) require.NoError(t, err) - require.EqualValues(t, ParseParentBatchIndex(bs), 14203) + require.Zero(t, ParseParentBatchIndex(bs)) } func TestParseFBatchIndex(t *testing.T) { From f311846a9a182c2fe93974629ce0811e57611954 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:41:00 +0800 Subject: [PATCH 07/38] feat(derivation): resolve canonical rollup submissions --- node/derivation/calldata_fixture_test.go | 199 +++++++++ node/derivation/canonical_commit.go | 376 ++++++++++++++++++ node/derivation/canonical_commit_test.go | 225 +++++++++++ node/derivation/derivation.go | 257 ++++++++---- node/derivation/derivation_test.go | 3 + .../testdata/rollup_calldata_fixtures.json | 123 ++++++ node/types/batch.go | 10 + 7 files changed, 1125 insertions(+), 68 deletions(-) create mode 100644 node/derivation/calldata_fixture_test.go create mode 100644 node/derivation/canonical_commit.go create mode 100644 node/derivation/canonical_commit_test.go create mode 100644 node/derivation/testdata/rollup_calldata_fixtures.json diff --git a/node/derivation/calldata_fixture_test.go b/node/derivation/calldata_fixture_test.go new file mode 100644 index 000000000..4653f515d --- /dev/null +++ b/node/derivation/calldata_fixture_test.go @@ -0,0 +1,199 @@ +package derivation + +import ( + "encoding/json" + "errors" + "os" + "strings" + "testing" + + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + "github.com/stretchr/testify/require" + + "morph-l2/bindings/bindings" + "morph-l2/node/types" +) + +const targetCurrentRollupABI = `[ + {"type":"function","name":"commitBatch","stateMutability":"payable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]}],"outputs":[]}, + {"type":"function","name":"commitState","stateMutability":"nonpayable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]}],"outputs":[]}, + {"type":"function","name":"commitBatchWithProof","stateMutability":"nonpayable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]},{"name":"batchHeader","type":"bytes"},{"name":"batchProof","type":"bytes"}],"outputs":[]} +]` + +type calldataFixtureCorpus struct { + SchemaVersion int `json:"schemaVersion"` + Fixtures []calldataFixture `json:"fixtures"` +} + +type calldataFixture struct { + Name string `json:"name"` + Epoch string `json:"epoch"` + Selector string `json:"selector"` + Data string `json:"data"` + Expected calldataFixtureExpected `json:"expected"` +} + +type calldataFixtureExpected struct { + Version uint64 `json:"version"` + ParentBatchHeader string `json:"parentBatchHeader"` + BlockContexts string `json:"blockContexts"` + LastBlockNumber uint64 `json:"lastBlockNumber"` + NumL1Messages uint16 `json:"numL1Messages"` + PrevStateRoot string `json:"prevStateRoot"` + PostStateRoot string `json:"postStateRoot"` + WithdrawRoot string `json:"withdrawRoot"` +} + +func loadCalldataFixtureCorpus(t *testing.T) calldataFixtureCorpus { + t.Helper() + raw, err := os.ReadFile("testdata/rollup_calldata_fixtures.json") + require.NoError(t, err) + var corpus calldataFixtureCorpus + require.NoError(t, json.Unmarshal(raw, &corpus)) + require.Equal(t, 1, corpus.SchemaVersion) + require.Len(t, corpus.Fixtures, 8) + return corpus +} + +func newFixtureDerivation(t *testing.T) *Derivation { + t.Helper() + currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) + require.NoError(t, err) + preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) + legacyABI, err := types.LegacyRollupMetaData.GetAbi() + require.NoError(t, err) + beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() + require.NoError(t, err) + return &Derivation{ + rollupABI: ¤tABI, + preSubmitterRollupABI: preSubmitterABI, + legacyRollupABI: legacyABI, + beforeMoveBlockCtxABI: beforeMoveABI, + } +} + +func TestUnPackDataAllHistoricalAndCurrentSelectors(t *testing.T) { + d := newFixtureDerivation(t) + for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { + t.Run(fixture.Name, func(t *testing.T) { + data, err := hexutil.Decode(fixture.Data) + require.NoError(t, err) + require.Equal(t, fixture.Selector, hexutil.Encode(data[:4])) + + got, err := d.UnPackData(data) + require.NoError(t, err) + require.Equal(t, uint(fixture.Expected.Version), got.Version) + require.Equal(t, common.FromHex(fixture.Expected.ParentBatchHeader), []byte(got.ParentBatchHeader)) + expectedBlockContexts := fixture.Expected.BlockContexts + if expectedBlockContexts == "" { + expectedBlockContexts = "0x" + } + require.Equal(t, expectedBlockContexts, hexutil.Encode(got.BlockContexts)) + require.Equal(t, fixture.Expected.LastBlockNumber, got.LastBlockNumber) + require.Equal(t, fixture.Expected.NumL1Messages, got.NumL1Messages) + require.Equal(t, common.HexToHash(fixture.Expected.PrevStateRoot), got.PrevStateRoot) + require.Equal(t, common.HexToHash(fixture.Expected.PostStateRoot), got.PostStateRoot) + require.Equal(t, common.HexToHash(fixture.Expected.WithdrawRoot), got.WithdrawRoot) + }) + } +} + +func TestUnPackDataRejectsUnknownShortAndMalformedCalldata(t *testing.T) { + d := newFixtureDerivation(t) + for length := 0; length < 4; length++ { + _, err := d.UnPackData(make([]byte, length)) + require.ErrorIs(t, err, types.ErrNotCommitBatchTx) + } + _, err := d.UnPackData([]byte{0xde, 0xad, 0xbe, 0xef}) + require.ErrorIs(t, err, types.ErrNotCommitBatchTx) + + currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) + require.NoError(t, err) + _, err = d.UnPackData(currentABI.Methods["commitBatch"].ID) + require.Error(t, err) + require.False(t, errors.Is(err, types.ErrNotCommitBatchTx), "known selector with malformed arguments must not be reported as unknown") +} + +func TestUnPackDataMixedCutoverWindow(t *testing.T) { + d := newFixtureDerivation(t) + fixtures := make(map[string]string) + for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { + fixtures[fixture.Name] = fixture.Data + } + for _, name := range []string{ + "pre_submitter_commitBatch", + "current_commitBatch", + "pre_submitter_commitState", + "current_commitState", + "pre_submitter_commitBatchWithProof", + "current_commitBatchWithProof", + } { + data, err := hexutil.Decode(fixtures[name]) + require.NoError(t, err) + _, err = d.UnPackData(data) + require.NoError(t, err, name) + } +} + +func TestSubmissionSelectorClassification(t *testing.T) { + d := newFixtureDerivation(t) + for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { + data, err := hexutil.Decode(fixture.Data) + require.NoError(t, err) + switch fixture.Name { + case "pre_submitter_commitState", "pre_submitter_commitBatchWithProof", "current_commitState", "current_commitBatchWithProof": + require.True(t, d.isStoredSourceSubmission(data), fixture.Name) + case "current_commitBatch": + require.True(t, d.isCurrentFreshCommitBatch(data), fixture.Name) + default: + require.False(t, d.isStoredSourceSubmission(data), fixture.Name) + require.False(t, d.isCurrentFreshCommitBatch(data), fixture.Name) + } + } +} + +func TestRollupSelectorFreeze(t *testing.T) { + beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() + require.NoError(t, err) + legacyABI, err := types.LegacyRollupMetaData.GetAbi() + require.NoError(t, err) + require.Equal(t, "0x4a8d544f", hexutil.Encode(beforeMoveABI.Methods["commitBatch"].ID), "before-move selector") + require.Equal(t, "0xd63b3549", hexutil.Encode(legacyABI.Methods["commitBatch"].ID), "legacy selector") + + preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) + currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) + require.NoError(t, err) + + wantOld := map[string]string{ + "commitBatch": "0x428868b5", + "commitState": "0x1e8825be", + "commitBatchWithProof": "0x4e8f1d67", + } + wantNew := map[string]string{ + "commitBatch": "0x41f756da", + "commitState": "0x67caa37a", + "commitBatchWithProof": "0x1544ba3a", + } + for name := range wantOld { + require.Equal(t, wantOld[name], hexutil.Encode(preSubmitterABI.Methods[name].ID)) + require.Equal(t, wantNew[name], hexutil.Encode(currentABI.Methods[name].ID)) + require.NotEqual(t, preSubmitterABI.Methods[name].ID, currentABI.Methods[name].ID) + } +} + +func TestGeneratedRollupBindingUsesCurrentSelectors(t *testing.T) { + generatedABI, err := bindings.RollupMetaData.GetAbi() + require.NoError(t, err) + want := map[string]string{ + "commitBatch": "0x41f756da", + "commitState": "0x67caa37a", + "commitBatchWithProof": "0x1544ba3a", + } + for name, selector := range want { + require.Equal(t, selector, hexutil.Encode(generatedABI.Methods[name].ID), name) + } +} diff --git a/node/derivation/canonical_commit.go b/node/derivation/canonical_commit.go new file mode 100644 index 000000000..9d3b6b454 --- /dev/null +++ b/node/derivation/canonical_commit.go @@ -0,0 +1,376 @@ +package derivation + +import ( + "context" + "errors" + "fmt" + "math/big" + "slices" + "strings" + + "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/common" + eth "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" + geth "github.com/morph-l2/go-ethereum/eth" +) + +var ( + ErrSnapshotChanged = errors.New("fixed L1 snapshot changed") + ErrCanonicalCommitNotFound = errors.New("canonical CommitBatch log not found") + ErrStoredBlobSourceNotFound = errors.New("stored blob source not found") + ErrZeroBlobVersionedHash = errors.New("pre-cutover zero blob versioned hash") + zeroBlobVersionedHash = common.HexToHash("0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014") + canonicalResolverRollupABI = mustCanonicalResolverRollupABI() + canonicalCommitEventTopic = canonicalResolverRollupABI.Events["CommitBatch"].ID + canonicalRevertEventTopic = canonicalResolverRollupABI.Events["RevertBatch"].ID +) + +const canonicalResolverRollupABIJSON = `[ + {"type":"function","name":"committedBatches","stateMutability":"view","inputs":[{"name":"batchIndex","type":"uint256"}],"outputs":[{"name":"batchHash","type":"bytes32"}]}, + {"type":"function","name":"batchBlobVersionedHashes","stateMutability":"view","inputs":[{"name":"batchIndex","type":"uint256"}],"outputs":[{"name":"blobVersionedHash","type":"bytes32"}]}, + {"type":"event","name":"CommitBatch","anonymous":false,"inputs":[{"name":"batchIndex","type":"uint256","indexed":true},{"name":"batchHash","type":"bytes32","indexed":true}]}, + {"type":"event","name":"RevertBatch","anonymous":false,"inputs":[{"name":"batchIndex","type":"uint256","indexed":true},{"name":"batchHash","type":"bytes32","indexed":true}]} +]` + +func mustCanonicalResolverRollupABI() abi.ABI { + parsed, err := abi.JSON(strings.NewReader(canonicalResolverRollupABIJSON)) + if err != nil { + panic(err) + } + return parsed +} + +// FixedL1Snapshot pins both the number used by legacy JSON-RPC block-number +// calls and its hash. Every resolver verifies the hash before and after its +// reads, providing EIP-1898-equivalent fail-closed behavior on providers that +// do not support blockHash call options. +type FixedL1Snapshot struct { + Number uint64 + Hash common.Hash +} + +type CanonicalCommitClient interface { + HeaderByNumber(context.Context, *big.Int) (*eth.Header, error) + CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) + FilterLogs(context.Context, ethereum.FilterQuery) ([]eth.Log, error) +} + +type StoredBlobSourceClient interface { + CanonicalCommitClient + TransactionByHash(context.Context, common.Hash) (*eth.Transaction, bool, error) +} + +type CanonicalCommit struct { + BatchIndex uint64 + BatchHash common.Hash + Log eth.Log +} + +type StoredBlobSource struct { + BatchIndex uint64 + StoredHash common.Hash + CommitLog eth.Log + Tx *eth.Transaction + BlobHashes []common.Hash +} + +type RollupBatchDecoder func([]byte) (geth.RPCRollupBatch, error) + +func PinL1Snapshot(ctx context.Context, client CanonicalCommitClient, number uint64) (FixedL1Snapshot, error) { + header, err := client.HeaderByNumber(ctx, uint64Big(number)) + if err != nil { + return FixedL1Snapshot{}, err + } + if header == nil || header.Number == nil || header.Number.Uint64() != number { + return FixedL1Snapshot{}, fmt.Errorf("pin L1 snapshot %d: invalid header", number) + } + return FixedL1Snapshot{Number: number, Hash: header.Hash()}, nil +} + +func ResolveCanonicalCommit( + ctx context.Context, + client CanonicalCommitClient, + rollupAddress common.Address, + batchIndex uint64, + snapshotNumber uint64, +) (*CanonicalCommit, error) { + snapshot, err := PinL1Snapshot(ctx, client, snapshotNumber) + if err != nil { + return nil, err + } + return ResolveCanonicalCommitAtSnapshot(ctx, client, rollupAddress, batchIndex, snapshot) +} + +func ResolveCanonicalCommitAtSnapshot( + ctx context.Context, + client CanonicalCommitClient, + rollupAddress common.Address, + batchIndex uint64, + snapshot FixedL1Snapshot, +) (*CanonicalCommit, error) { + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + committedHash, err := readRollupHashAtSnapshot(ctx, client, rollupAddress, "committedBatches", batchIndex, snapshot.Number) + if err != nil { + return nil, err + } + if committedHash == (common.Hash{}) { + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + return nil, nil + } + + logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{ + FromBlock: uint64Big(0), + ToBlock: uint64Big(snapshot.Number), + Addresses: []common.Address{rollupAddress}, + Topics: [][]common.Hash{ + {canonicalCommitEventTopic, canonicalRevertEventTopic}, + {common.BigToHash(uint64Big(batchIndex))}, + }, + }) + if err != nil { + return nil, err + } + ordered, err := validateAndSortLifecycleLogs(logs, rollupAddress, batchIndex, snapshot.Number) + if err != nil { + return nil, err + } + + lastRevert := -1 + for i := range ordered { + if ordered[i].Topics[0] == canonicalRevertEventTopic { + lastRevert = i + } + } + var selected *eth.Log + for i := lastRevert + 1; i < len(ordered); i++ { + log := ordered[i] + if log.Topics[0] == canonicalCommitEventTopic && log.Topics[2] == committedHash { + candidate := log + selected = &candidate + } + } + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + if selected == nil { + return nil, fmt.Errorf("%w: batch %d, getter hash %s", ErrCanonicalCommitNotFound, batchIndex, committedHash.Hex()) + } + return &CanonicalCommit{ + BatchIndex: batchIndex, + BatchHash: committedHash, + Log: *selected, + }, nil +} + +// ResolveStoredBlobSource deliberately does not apply the canonical resolver's +// "after the last Revert" filter. Rollup retains batchBlobVersionedHashes so a +// later blobless commitState/commitBatchWithProof can reuse a blob originally +// published by a pre-Revert Commit. The source remains identified by its full +// canonical L1 log and transaction identity. +func ResolveStoredBlobSource( + ctx context.Context, + client StoredBlobSourceClient, + rollupAddress common.Address, + batchIndex uint64, + snapshotNumber uint64, + decode RollupBatchDecoder, +) (*StoredBlobSource, error) { + snapshot, err := PinL1Snapshot(ctx, client, snapshotNumber) + if err != nil { + return nil, err + } + return ResolveStoredBlobSourceAtSnapshot(ctx, client, rollupAddress, batchIndex, snapshot, decode) +} + +func ResolveStoredBlobSourceAtSnapshot( + ctx context.Context, + client StoredBlobSourceClient, + rollupAddress common.Address, + batchIndex uint64, + snapshot FixedL1Snapshot, + decode RollupBatchDecoder, +) (*StoredBlobSource, error) { + if decode == nil { + return nil, errors.New("rollup batch decoder is nil") + } + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + storedHash, err := readRollupHashAtSnapshot(ctx, client, rollupAddress, "batchBlobVersionedHashes", batchIndex, snapshot.Number) + if err != nil { + return nil, err + } + if storedHash == (common.Hash{}) || storedHash == zeroBlobVersionedHash { + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + if storedHash == zeroBlobVersionedHash { + return nil, ErrZeroBlobVersionedHash + } + return nil, fmt.Errorf("%w: batch %d has no stored hash", ErrStoredBlobSourceNotFound, batchIndex) + } + + logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{ + FromBlock: uint64Big(0), + ToBlock: uint64Big(snapshot.Number), + Addresses: []common.Address{rollupAddress}, + Topics: [][]common.Hash{ + {canonicalCommitEventTopic}, + {common.BigToHash(uint64Big(batchIndex))}, + }, + }) + if err != nil { + return nil, err + } + ordered, err := validateAndSortLifecycleLogs(logs, rollupAddress, batchIndex, snapshot.Number) + if err != nil { + return nil, err + } + + var source *StoredBlobSource + for i := len(ordered) - 1; i >= 0; i-- { + log := ordered[i] + if log.Topics[0] != canonicalCommitEventTopic { + continue + } + tx, pending, err := client.TransactionByHash(ctx, log.TxHash) + if err != nil { + return nil, err + } + if pending || tx == nil { + return nil, fmt.Errorf("stored blob source transaction %s is pending or missing", log.TxHash.Hex()) + } + if tx.Hash() != log.TxHash { + return nil, fmt.Errorf("stored blob source transaction hash mismatch: requested %s, got %s", log.TxHash.Hex(), tx.Hash().Hex()) + } + blobHashes := tx.BlobHashes() + if len(blobHashes) == 0 { + continue + } + batch, err := decode(tx.Data()) + if err != nil { + return nil, fmt.Errorf("decode stored blob source transaction %s: %w", log.TxHash.Hex(), err) + } + if !storedBlobHashMatches(uint(batch.Version), blobHashes, storedHash) { + continue + } + source = &StoredBlobSource{ + BatchIndex: batchIndex, + StoredHash: storedHash, + CommitLog: log, + Tx: tx, + BlobHashes: slices.Clone(blobHashes), + } + break + } + if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { + return nil, err + } + if source == nil { + return nil, fmt.Errorf("%w: batch %d, stored hash %s", ErrStoredBlobSourceNotFound, batchIndex, storedHash.Hex()) + } + return source, nil +} + +func storedBlobHashMatches(version uint, blobHashes []common.Hash, storedHash common.Hash) bool { + if len(blobHashes) == 0 { + return false + } + if version != 2 { + return len(blobHashes) == 1 && blobHashes[0] == storedHash + } + encoded := make([]byte, 0, len(blobHashes)*common.HashLength) + for _, hash := range blobHashes { + encoded = append(encoded, hash[:]...) + } + return crypto.Keccak256Hash(encoded) == storedHash +} + +func readRollupHashAtSnapshot( + ctx context.Context, + client CanonicalCommitClient, + rollupAddress common.Address, + method string, + batchIndex uint64, + snapshotNumber uint64, +) (common.Hash, error) { + input, err := canonicalResolverRollupABI.Pack(method, uint64Big(batchIndex)) + if err != nil { + return common.Hash{}, err + } + output, err := client.CallContract(ctx, ethereum.CallMsg{To: &rollupAddress, Data: input}, uint64Big(snapshotNumber)) + if err != nil { + return common.Hash{}, err + } + if len(output) != common.HashLength { + return common.Hash{}, fmt.Errorf("%s returned %d bytes, want %d", method, len(output), common.HashLength) + } + values, err := canonicalResolverRollupABI.Methods[method].Outputs.Unpack(output) + if err != nil { + return common.Hash{}, err + } + if len(values) != 1 { + return common.Hash{}, fmt.Errorf("%s returned %d values, want 1", method, len(values)) + } + decoded := *abi.ConvertType(values[0], new([32]byte)).(*[32]byte) + return common.Hash(decoded), nil +} + +func validateAndSortLifecycleLogs(logs []eth.Log, rollupAddress common.Address, batchIndex, snapshotNumber uint64) ([]eth.Log, error) { + indexTopic := common.BigToHash(uint64Big(batchIndex)) + ordered := slices.Clone(logs) + for i := range ordered { + log := ordered[i] + if log.Removed { + return nil, fmt.Errorf("removed lifecycle log at %d/%d/%d", log.BlockNumber, log.TxIndex, log.Index) + } + if log.Address != rollupAddress || log.BlockNumber > snapshotNumber || len(log.Topics) != 3 || log.Topics[1] != indexTopic { + return nil, fmt.Errorf("malformed lifecycle log at %d/%d/%d", log.BlockNumber, log.TxIndex, log.Index) + } + if log.Topics[0] != canonicalCommitEventTopic && log.Topics[0] != canonicalRevertEventTopic { + return nil, fmt.Errorf("unexpected lifecycle topic %s", log.Topics[0].Hex()) + } + } + slices.SortFunc(ordered, func(a, b eth.Log) int { + if a.BlockNumber != b.BlockNumber { + return compareUint64(a.BlockNumber, b.BlockNumber) + } + if a.TxIndex != b.TxIndex { + return compareUint64(uint64(a.TxIndex), uint64(b.TxIndex)) + } + return compareUint64(uint64(a.Index), uint64(b.Index)) + }) + return ordered, nil +} + +func verifyL1Snapshot(ctx context.Context, client CanonicalCommitClient, snapshot FixedL1Snapshot) error { + header, err := client.HeaderByNumber(ctx, uint64Big(snapshot.Number)) + if err != nil { + return err + } + if header == nil || header.Number == nil || header.Number.Uint64() != snapshot.Number || header.Hash() != snapshot.Hash { + return fmt.Errorf("%w: block %d expected %s", ErrSnapshotChanged, snapshot.Number, snapshot.Hash.Hex()) + } + return nil +} + +func uint64Big(value uint64) *big.Int { + return new(big.Int).SetUint64(value) +} + +func compareUint64(a, b uint64) int { + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } +} diff --git a/node/derivation/canonical_commit_test.go b/node/derivation/canonical_commit_test.go new file mode 100644 index 000000000..d62565481 --- /dev/null +++ b/node/derivation/canonical_commit_test.go @@ -0,0 +1,225 @@ +package derivation + +import ( + "context" + "math/big" + "testing" + + "github.com/holiman/uint256" + "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + eth "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" + "github.com/stretchr/testify/require" +) + +type resolverFakeClient struct { + header *eth.Header + changedHeader *eth.Header + changeAfterCall int + headerCalls int + callHash common.Hash + logs []eth.Log + filterCalls int + lastQuery ethereum.FilterQuery + transactions map[common.Hash]*eth.Transaction +} + +func (f *resolverFakeClient) HeaderByNumber(context.Context, *big.Int) (*eth.Header, error) { + f.headerCalls++ + if f.changedHeader != nil && f.changeAfterCall > 0 && f.headerCalls >= f.changeAfterCall { + return f.changedHeader, nil + } + return f.header, nil +} + +func (f *resolverFakeClient) CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) { + return canonicalResolverRollupABI.Methods["committedBatches"].Outputs.Pack(f.callHash) +} + +func (f *resolverFakeClient) FilterLogs(_ context.Context, query ethereum.FilterQuery) ([]eth.Log, error) { + f.filterCalls++ + f.lastQuery = query + filtered := make([]eth.Log, 0, len(f.logs)) + for _, log := range f.logs { + if len(query.Addresses) > 0 && log.Address != query.Addresses[0] { + continue + } + matched := true + for position, alternatives := range query.Topics { + if len(alternatives) == 0 { + continue + } + if len(log.Topics) <= position { + matched = false + break + } + positionMatched := false + for _, topic := range alternatives { + if log.Topics[position] == topic { + positionMatched = true + break + } + } + if !positionMatched { + matched = false + break + } + } + if matched { + filtered = append(filtered, log) + } + } + return filtered, nil +} + +func (f *resolverFakeClient) TransactionByHash(_ context.Context, hash common.Hash) (*eth.Transaction, bool, error) { + return f.transactions[hash], false, nil +} + +func resolverTestHeader(number uint64, marker byte) *eth.Header { + return ð.Header{Number: new(big.Int).SetUint64(number), Time: number, Extra: []byte{marker}} +} + +func resolverTestLog(address common.Address, event, hash common.Hash, index, block uint64, txIndex, logIndex uint) eth.Log { + return eth.Log{ + Address: address, + Topics: []common.Hash{event, common.BigToHash(uint64Big(index)), hash}, + BlockNumber: block, + TxIndex: txIndex, + Index: logIndex, + } +} + +func TestResolveCanonicalCommitAfterLastRevertWithSameHashRecommit(t *testing.T) { + const snapshotNumber = uint64(100) + const batchIndex = uint64(7) + rollupAddress := common.HexToAddress("0x1234") + batchHash := common.HexToHash("0xaaaa") + wrongHash := common.HexToHash("0xbbbb") + wantTx := common.HexToHash("0x3333") + + oldCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, batchHash, batchIndex, 10, 0, 0) + revert := resolverTestLog(rollupAddress, canonicalRevertEventTopic, batchHash, batchIndex, 11, 0, 0) + wrongCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, wrongHash, batchIndex, 12, 0, 0) + recommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, batchHash, batchIndex, 12, 1, 3) + recommit.TxHash = wantTx + client := &resolverFakeClient{ + header: resolverTestHeader(snapshotNumber, 1), + callHash: batchHash, + logs: []eth.Log{recommit, oldCommit, wrongCommit, revert}, // deliberately unsorted + } + + got, err := ResolveCanonicalCommit(context.Background(), client, rollupAddress, batchIndex, snapshotNumber) + require.NoError(t, err) + require.NotNil(t, got) + require.Equal(t, batchHash, got.BatchHash) + require.Equal(t, wantTx, got.Log.TxHash, "same-hash recommit must be identified by its post-Revert log") + require.Equal(t, snapshotNumber, client.lastQuery.ToBlock.Uint64()) + require.Equal(t, 3, client.headerCalls, "snapshot must be pinned and verified before/after reads") +} + +func TestResolveCanonicalCommitReturnsNilForZeroGetter(t *testing.T) { + client := &resolverFakeClient{header: resolverTestHeader(100, 1)} + got, err := ResolveCanonicalCommit(context.Background(), client, common.HexToAddress("0x1234"), 1, 100) + require.NoError(t, err) + require.Nil(t, got) + require.Zero(t, client.filterCalls, "zero committedBatches must not scan logs") +} + +func TestResolveCanonicalCommitRejectsChangedSnapshot(t *testing.T) { + client := &resolverFakeClient{ + header: resolverTestHeader(100, 1), + changedHeader: resolverTestHeader(100, 2), + changeAfterCall: 3, + callHash: common.HexToHash("0xaaaa"), + logs: []eth.Log{ + resolverTestLog(common.HexToAddress("0x1234"), canonicalCommitEventTopic, common.HexToHash("0xaaaa"), 1, 10, 0, 0), + }, + } + _, err := ResolveCanonicalCommit(context.Background(), client, common.HexToAddress("0x1234"), 1, 100) + require.ErrorIs(t, err, ErrSnapshotChanged) +} + +func TestResolveStoredBlobSourceSearchesBeforeRevert(t *testing.T) { + const snapshotNumber = uint64(100) + const batchIndex = uint64(7) + rollupAddress := common.HexToAddress("0x1234") + corpus := loadCalldataFixtureCorpus(t) + fixtureData := make(map[string][]byte, len(corpus.Fixtures)) + for _, fixture := range corpus.Fixtures { + data, err := hexutil.Decode(fixture.Data) + require.NoError(t, err) + fixtureData[fixture.Name] = data + } + + blobHashes := []common.Hash{common.HexToHash("0x1111"), common.HexToHash("0x2222")} + storedHashBytes := make([]byte, 0, len(blobHashes)*common.HashLength) + for _, hash := range blobHashes { + storedHashBytes = append(storedHashBytes, hash[:]...) + } + storedHash := crypto.Keccak256Hash(storedHashBytes) + originalTx := newResolverBlobTx(1, fixtureData["pre_submitter_commitBatch"], blobHashes) + bloblessTx := eth.NewTx(ð.LegacyTx{Nonce: 2, To: &rollupAddress, Data: fixtureData["current_commitState"]}) + + originalCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, common.HexToHash("0xaaaa"), batchIndex, 10, 0, 0) + originalCommit.TxHash = originalTx.Hash() + revert := resolverTestLog(rollupAddress, canonicalRevertEventTopic, common.HexToHash("0xaaaa"), batchIndex, 11, 0, 0) + bloblessRecommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, common.HexToHash("0xbbbb"), batchIndex, 12, 0, 0) + bloblessRecommit.TxHash = bloblessTx.Hash() + client := &resolverFakeClient{ + header: resolverTestHeader(snapshotNumber, 1), + callHash: storedHash, + logs: []eth.Log{bloblessRecommit, revert, originalCommit}, + transactions: map[common.Hash]*eth.Transaction{ + originalTx.Hash(): originalTx, + bloblessTx.Hash(): bloblessTx, + }, + } + d := newFixtureDerivation(t) + + source, err := ResolveStoredBlobSource(context.Background(), client, rollupAddress, batchIndex, snapshotNumber, d.UnPackData) + require.NoError(t, err) + require.Equal(t, originalTx.Hash(), source.CommitLog.TxHash) + require.Equal(t, blobHashes, source.BlobHashes) + require.Equal(t, []common.Hash{canonicalCommitEventTopic}, client.lastQuery.Topics[0], + "stored-source lookup must scan every historical Commit and must not reuse the post-Revert canonical filter") +} + +func TestResolveStoredBlobSourcePreservesZeroHashSpecialCase(t *testing.T) { + client := &resolverFakeClient{ + header: resolverTestHeader(100, 1), + callHash: zeroBlobVersionedHash, + } + _, err := ResolveStoredBlobSource(context.Background(), client, common.HexToAddress("0x1234"), 1, 100, newFixtureDerivation(t).UnPackData) + require.ErrorIs(t, err, ErrZeroBlobVersionedHash) + require.Zero(t, client.filterCalls) +} + +func TestStoredBlobHashMatchesLegacyAndV2(t *testing.T) { + hashes := []common.Hash{common.HexToHash("0x1111"), common.HexToHash("0x2222")} + require.True(t, storedBlobHashMatches(1, hashes[:1], hashes[0])) + require.False(t, storedBlobHashMatches(1, hashes[:1], hashes[1])) + encoded := append(append([]byte{}, hashes[0][:]...), hashes[1][:]...) + require.True(t, storedBlobHashMatches(2, hashes, crypto.Keccak256Hash(encoded))) + require.False(t, storedBlobHashMatches(2, hashes, hashes[0])) +} + +func newResolverBlobTx(nonce uint64, data []byte, blobHashes []common.Hash) *eth.Transaction { + return eth.NewTx(ð.BlobTx{ + ChainID: uint256.NewInt(1), + Nonce: nonce, + GasTipCap: uint256.NewInt(1), + GasFeeCap: uint256.NewInt(2), + Gas: 100_000, + To: common.HexToAddress("0x1234"), + Value: uint256.NewInt(0), + Data: data, + BlobFeeCap: uint256.NewInt(1), + BlobHashes: blobHashes, + V: uint256.NewInt(0), + R: uint256.NewInt(0), + S: uint256.NewInt(0), + }) +} diff --git a/node/derivation/derivation.go b/node/derivation/derivation.go index b050f3483..c2dab2f08 100644 --- a/node/derivation/derivation.go +++ b/node/derivation/derivation.go @@ -24,6 +24,7 @@ import ( "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" + commonbatch "morph-l2/common/batch" nodecommon "morph-l2/node/common" "morph-l2/node/sync" "morph-l2/node/types" @@ -49,6 +50,7 @@ type Derivation struct { L2ToL1MessagePasser *bindings.L2ToL1MessagePasser rollupABI *abi.ABI + preSubmitterRollupABI *abi.ABI legacyRollupABI *abi.ABI // before remove skipMap beforeMoveBlockCtxABI *abi.ABI @@ -112,6 +114,10 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, if err != nil { return nil, err } + preSubmitterRollupAbi, err := types.PreSubmitterRollupMetaData.GetAbi() + if err != nil { + return nil, err + } beforeMoveBlockCtxAbi, err := types.BeforeMoveBlockCtxABI.GetAbi() if err != nil { return nil, err @@ -135,6 +141,7 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, syncer: syncer, rollup: rollup, rollupABI: rollupAbi, + preSubmitterRollupABI: preSubmitterRollupAbi, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxAbi, logger: logger, @@ -309,6 +316,10 @@ func (d *Derivation) derivationBlock(ctx context.Context) { d.logger.Error("fetch batch info outline failed", "err", err) return } + if err := d.hydrateStoredBlobHashes(ctx, batchInfo, lg.TxHash, lg.BlockNumber); err != nil { + d.logger.Error("resolve stored blob source failed", "batchIndex", batchInfo.batchIndex, "err", err) + return + } d.logger.Info("local verify fetched batch metadata", "batchIndex", batchInfo.batchIndex, "version", batchInfo.version, @@ -552,30 +563,63 @@ func (d *Derivation) fetchRollupDataByTxHash(txHash common.Hash, blockNumber uin return nil, err } - // Get block header to retrieve timestamp - header, err := d.l1Client.HeaderByNumber(d.ctx, big.NewInt(int64(blockNumber))) - if err != nil { - return nil, err - } - // Get transaction blob hashes blobHashes := tx.BlobHashes() + blobSourceTx := tx + blobSourceBlockNumber := blockNumber + if len(blobHashes) == 0 && d.isCurrentFreshCommitBatch(tx.Data()) { + return nil, fmt.Errorf("current commitBatch %s has no fresh blob", txHash.Hex()) + } + if len(blobHashes) == 0 && d.isStoredSourceSubmission(tx.Data()) { + parentBatchIndex, indexErr := commonbatch.BatchHeaderBytes(batch.ParentBatchHeader).BatchIndex() + if indexErr != nil { + return nil, fmt.Errorf("resolve stored blob source batch index: %w", indexErr) + } + source, sourceErr := ResolveStoredBlobSource( + d.ctx, + d.l1Client, + d.RollupContractAddress, + parentBatchIndex+1, + blockNumber, + d.UnPackData, + ) + if sourceErr != nil && !errors.Is(sourceErr, ErrZeroBlobVersionedHash) { + return nil, sourceErr + } + if source != nil { + blobSourceTx = source.Tx + blobSourceBlockNumber = source.CommitLog.BlockNumber + blobHashes = source.BlobHashes + d.logger.Info("recovered stored blob source", + "batchIndex", parentBatchIndex+1, + "commitTxHash", txHash, + "sourceTxHash", source.CommitLog.TxHash, + "sourceBlockNumber", source.CommitLog.BlockNumber) + } + } if len(blobHashes) > 0 { - d.logger.Info("Transaction contains blobs", "txHash", txHash, "blobCount", len(blobHashes)) + d.logger.Info("Transaction contains blobs", "txHash", blobSourceTx.Hash(), "blobCount", len(blobHashes)) + + // Retrieve the timestamp and blob index positions from the transaction + // that actually published the blobs, not from a later blobless commit. + header, err := d.l1Client.HeaderByNumber(d.ctx, big.NewInt(int64(blobSourceBlockNumber))) + if err != nil { + return nil, err + } // Initialize indexedBlobHashes as nil var indexedBlobHashes []IndexedBlobHash // Only try to build IndexedBlobHash array if not forcing get all blobs // Try to get the block to build IndexedBlobHash array - block, err := d.l1Client.BlockByNumber(d.ctx, big.NewInt(int64(blockNumber))) + block, err := d.l1Client.BlockByNumber(d.ctx, big.NewInt(int64(blobSourceBlockNumber))) if err == nil { // Successfully got the block, now build IndexedBlobHash array - d.logger.Info("Building IndexedBlobHash array from block", "blockNumber", blockNumber) - indexedBlobHashes = dataAndHashesFromTxs(block.Transactions(), tx) + d.logger.Info("Building IndexedBlobHash array from block", "blockNumber", blobSourceBlockNumber) + indexedBlobHashes = dataAndHashesFromTxs(block.Transactions(), blobSourceTx) d.logger.Info("Built IndexedBlobHash array", "count", len(indexedBlobHashes)) } else { - d.logger.Info("Failed to get block, will try fetching all blobs", "blockNumber", blockNumber, "error", err) + d.logger.Info("Failed to get block, will try fetching all blobs", "blockNumber", blobSourceBlockNumber, "error", err) } // Get all blobs corresponding to this timestamp, content-verified @@ -599,25 +643,86 @@ func (d *Derivation) fetchRollupDataByTxHash(txHash common.Hash, blockNumber uin rollupData.l1BlockNumber = blockNumber rollupData.txHash = txHash rollupData.nonce = tx.Nonce() - rollupData.blobHashes = tx.BlobHashes() + rollupData.blobHashes = blobHashes return rollupData, nil } +func (d *Derivation) hydrateStoredBlobHashes(ctx context.Context, batchInfo *BatchInfo, txHash common.Hash, blockNumber uint64) error { + if batchInfo == nil || len(batchInfo.blobHashes) > 0 { + return nil + } + tx, pending, err := d.l1Client.TransactionByHash(ctx, txHash) + if err != nil { + return err + } + if pending || tx == nil { + return errors.New("pending or missing rollup transaction") + } + if d.isCurrentFreshCommitBatch(tx.Data()) { + return fmt.Errorf("current commitBatch %s has no fresh blob", txHash.Hex()) + } + if !d.isStoredSourceSubmission(tx.Data()) { + return nil + } + source, err := ResolveStoredBlobSource( + ctx, + d.l1Client, + d.RollupContractAddress, + batchInfo.batchIndex, + blockNumber, + d.UnPackData, + ) + if errors.Is(err, ErrZeroBlobVersionedHash) { + return nil // frozen pre-cutover ZERO_VERSIONED_HASH branch + } + if err != nil { + return err + } + batchInfo.blobHashes = source.BlobHashes + return nil +} + +func (d *Derivation) isStoredSourceSubmission(data []byte) bool { + return matchesRollupMethodSelector(d.preSubmitterRollupABI, data, "commitState", "commitBatchWithProof") || + matchesRollupMethodSelector(d.rollupABI, data, "commitState", "commitBatchWithProof") +} + +func (d *Derivation) isCurrentFreshCommitBatch(data []byte) bool { + if !matchesRollupMethodSelector(d.rollupABI, data, "commitBatch") { + return false + } + // Until bindings are regenerated in a mixed development checkout, the + // current and frozen ABI may temporarily have the same old selector. Never + // reinterpret that frozen historical selector as the fresh-blob-only call. + return !matchesRollupMethodSelector(d.preSubmitterRollupABI, data, "commitBatch") +} + +func matchesRollupMethodSelector(contractABI *abi.ABI, data []byte, methodNames ...string) bool { + if contractABI == nil || len(data) < 4 { + return false + } + for _, name := range methodNames { + if method, ok := contractABI.Methods[name]; ok && bytes.Equal(method.ID, data[:4]) { + return true + } + } + return false +} + func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { var batch geth.RPCRollupBatch + if len(data) < 4 { + return batch, types.ErrNotCommitBatchTx + } if bytes.Equal(d.beforeMoveBlockCtxABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.beforeMoveBlockCtxABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { return batch, fmt.Errorf("submitBatches Unpack error:%v", err) } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - BlockContexts []uint8 "json:\"blockContexts\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) + if len(args) == 0 { + return batch, errors.New("commitBatch has no batchDataInput") + } + rollupBatchData := *abi.ConvertType(args[0], new(beforeMoveBatchDataInput)).(*beforeMoveBatchDataInput) batch = geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, @@ -626,20 +731,16 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } + return batch, nil } else if bytes.Equal(d.legacyRollupABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.legacyRollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { return batch, fmt.Errorf("submitBatches Unpack error:%v", err) } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - BlockContexts []uint8 "json:\"blockContexts\"" - SkippedL1MessageBitmap []uint8 "json:\"skippedL1MessageBitmap\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) + if len(args) == 0 { + return batch, errors.New("commitBatch has no batchDataInput") + } + rollupBatchData := *abi.ConvertType(args[0], new(legacyBatchDataInput)).(*legacyBatchDataInput) batch = geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, @@ -648,44 +749,66 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } - } else if bytes.Equal(d.rollupABI.Methods["commitBatch"].ID, data[:4]) { - args, err := d.rollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) + return batch, nil + } else if decoded, matched, err := unpackModernRollupCall(d.preSubmitterRollupABI, data); matched { + return decoded, err + } else if decoded, matched, err := unpackModernRollupCall(d.rollupABI, data); matched { + return decoded, err + } + return batch, types.ErrNotCommitBatchTx +} + +type beforeMoveBatchDataInput struct { + Version uint8 + ParentBatchHeader []byte + BlockContexts []byte + PrevStateRoot [32]byte + PostStateRoot [32]byte + WithdrawalRoot [32]byte +} + +type legacyBatchDataInput struct { + Version uint8 + ParentBatchHeader []byte + BlockContexts []byte + SkippedL1MessageBitmap []byte + PrevStateRoot [32]byte + PostStateRoot [32]byte + WithdrawalRoot [32]byte +} + +type modernBatchDataInput struct { + Version uint8 + ParentBatchHeader []byte + LastBlockNumber uint64 + NumL1Messages uint16 + PrevStateRoot [32]byte + PostStateRoot [32]byte + WithdrawalRoot [32]byte +} + +// unpackModernRollupCall recognizes all three modern submission entrypoints. +// Pre-submitter and current ABIs are passed separately so their selectors stay +// independently frozen; only args[0] (BatchDataInput) is consumed. +func unpackModernRollupCall(contractABI *abi.ABI, data []byte) (geth.RPCRollupBatch, bool, error) { + var batch geth.RPCRollupBatch + if contractABI == nil || len(data) < 4 { + return batch, false, nil + } + for _, methodName := range []string{"commitBatch", "commitState", "commitBatchWithProof"} { + method, ok := contractABI.Methods[methodName] + if !ok || !bytes.Equal(method.ID, data[:4]) { + continue + } + args, err := method.Inputs.Unpack(data[4:]) if err != nil { - return batch, fmt.Errorf("submitBatches Unpack error:%v", err) + return batch, true, fmt.Errorf("%s Unpack error:%v", methodName, err) } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - LastBlockNumber uint64 "json:\"lastBlockNumber\"" - NumL1Messages uint16 "json:\"numL1Messages\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) - batch = geth.RPCRollupBatch{ - Version: uint(rollupBatchData.Version), - ParentBatchHeader: rollupBatchData.ParentBatchHeader, - LastBlockNumber: rollupBatchData.LastBlockNumber, - NumL1Messages: rollupBatchData.NumL1Messages, - PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), - PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), - WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), + if len(args) == 0 { + return batch, true, fmt.Errorf("%s has no batchDataInput", methodName) } - } else if bytes.Equal(d.rollupABI.Methods["commitBatchWithProof"].ID, data[:4]) { - args, err := d.rollupABI.Methods["commitBatchWithProof"].Inputs.Unpack(data[4:]) - if err != nil { - return batch, fmt.Errorf("commitBatchWithProof Unpack error:%v", err) - } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - LastBlockNumber uint64 "json:\"lastBlockNumber\"" - NumL1Messages uint16 "json:\"numL1Messages\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) - batch = geth.RPCRollupBatch{ + rollupBatchData := *abi.ConvertType(args[0], new(modernBatchDataInput)).(*modernBatchDataInput) + return geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, LastBlockNumber: rollupBatchData.LastBlockNumber, @@ -693,11 +816,9 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), - } - } else { - return batch, types.ErrNotCommitBatchTx + }, true, nil } - return batch, nil + return batch, false, nil } func (d *Derivation) parseBatch(batch geth.RPCRollupBatch) (*BatchInfo, error) { diff --git a/node/derivation/derivation_test.go b/node/derivation/derivation_test.go index 69eb750d6..d70b88d99 100644 --- a/node/derivation/derivation_test.go +++ b/node/derivation/derivation_test.go @@ -21,10 +21,13 @@ func TestUnPackData(t *testing.T) { require.NoError(t, err) legacyRollupAbi, err := types.LegacyRollupMetaData.GetAbi() require.NoError(t, err) + preSubmitterRollupABI, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) beforeMoveBlockCtxABI, err := types.BeforeMoveBlockCtxABI.GetAbi() require.NoError(t, err) d := Derivation{ rollupABI: rollupAbi, + preSubmitterRollupABI: preSubmitterRollupABI, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxABI, } diff --git a/node/derivation/testdata/rollup_calldata_fixtures.json b/node/derivation/testdata/rollup_calldata_fixtures.json new file mode 100644 index 000000000..b728a2023 --- /dev/null +++ b/node/derivation/testdata/rollup_calldata_fixtures.json @@ -0,0 +1,123 @@ +{ + "schemaVersion": 1, + "fixtures": [ + { + "name": "before_move_commitBatch", + "epoch": "before-move", + "selector": "0x4a8d544f", + "data": "0x4a8d544f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 0, + "parentBatchHeader": "0x010203", + "blockContexts": "0xaabb", + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "legacy_commitBatch", + "epoch": "legacy", + "selector": "0xd63b3549", + "data": "0xd63b3549000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 1, + "parentBatchHeader": "0x010203", + "blockContexts": "0xaabb", + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "pre_submitter_commitBatch", + "epoch": "pre-submitter", + "selector": "0x428868b5", + "data": "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "pre_submitter_commitState", + "epoch": "pre-submitter", + "selector": "0x1e8825be", + "data": "0x1e8825be00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "pre_submitter_commitBatchWithProof", + "epoch": "pre-submitter", + "selector": "0x4e8f1d67", + "data": "0x4e8f1d67000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "current_commitBatch", + "epoch": "current", + "selector": "0x41f756da", + "data": "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "current_commitState", + "epoch": "current", + "selector": "0x67caa37a", + "data": "0x67caa37a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "current_commitBatchWithProof", + "epoch": "current", + "selector": "0x1544ba3a", + "data": "0x1544ba3a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + } + ] +} diff --git a/node/types/batch.go b/node/types/batch.go index 3038dbb74..a7785a19f 100644 --- a/node/types/batch.go +++ b/node/types/batch.go @@ -1,10 +1,20 @@ package types import ( + _ "embed" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" ) +//go:embed abi/pre_submitter_rollup.json +var preSubmitterRollupABI string + var ( + // PreSubmitterRollupMetaData is the immutable production ABI immediately + // before BatchSignatureInput was removed. Historical calldata decoding must + // never be coupled to the regenerated current Rollup binding. + PreSubmitterRollupMetaData = &bind.MetaData{ABI: preSubmitterRollupABI} + LegacyRollupMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorIncorrectBatchLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorNoBlockInBatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"blockContexts\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", } From 0fd2039766215028ea36138af3ebe8de25298adb Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:48:19 +0800 Subject: [PATCH 08/38] feat(prover): resolve canonical submitter cutover batches --- prover/Makefile | 6 +- prover/bin/challenge/.env.dev | 4 + prover/bin/challenge/src/abi/Rollup.json | 288 +++++++- prover/bin/challenge/src/abi/Submitter.json | 660 ++++++++++++++++++ prover/bin/challenge/src/abi/mod.rs | 10 + .../bin/challenge/src/bin/auto_challenge.rs | 103 +-- prover/bin/challenge/src/external_sign.rs | 3 +- prover/bin/challenge/src/handler.rs | 249 ++++--- prover/bin/challenge/src/lib.rs | 4 +- prover/bin/challenge/src/rollup_compat.rs | 253 +++++++ prover/bin/challenge/src/util.rs | 1 + prover/bin/shadow-prove/.env.dev | 5 +- prover/bin/shadow-prove/abi/Rollup.json | 196 ++++-- prover/bin/shadow-prove/src/abi.rs | 10 + prover/bin/shadow-prove/src/execute.rs | 10 +- prover/bin/shadow-prove/src/lib.rs | 1 + prover/bin/shadow-prove/src/main.rs | 12 +- prover/bin/shadow-prove/src/rollup_compat.rs | 334 +++++++++ prover/bin/shadow-prove/src/shadow_prove.rs | 21 +- prover/bin/shadow-prove/src/shadow_rollup.rs | 525 +++++++------- prover/bin/shadow-prove/src/util.rs | 1 + 21 files changed, 2223 insertions(+), 473 deletions(-) create mode 100644 prover/bin/challenge/src/abi/Submitter.json create mode 100644 prover/bin/challenge/src/rollup_compat.rs create mode 100644 prover/bin/shadow-prove/src/rollup_compat.rs diff --git a/prover/Makefile b/prover/Makefile index d55f0bb46..6328e1661 100644 --- a/prover/Makefile +++ b/prover/Makefile @@ -1,3 +1,5 @@ +RUST_TOOLCHAIN ?= 1.91.0 + start-server: docker compose -f docker-compose-app.yml up -d @@ -6,7 +8,7 @@ stop-server: build-shadow-prove: - cd bin/shadow-prove && cargo build --release + cd bin/shadow-prove && cargo +$(RUST_TOOLCHAIN) build --release build-challenge: - cd bin/challenge && cargo build --release + cd bin/challenge && cargo +$(RUST_TOOLCHAIN) build --release diff --git a/prover/bin/challenge/.env.dev b/prover/bin/challenge/.env.dev index b5224a629..847cbb13e 100644 --- a/prover/bin/challenge/.env.dev +++ b/prover/bin/challenge/.env.dev @@ -3,12 +3,16 @@ HANDLER_L1_RPC = "http://localhost:8545" HANDLER_L2_RPC = "http://localhost:8545" HANDLER_PROVER_RPC ="http://localhost:3030" HANDLER_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" +# Development fixture only. Production must use the archived Rollup proxy +# deployment block from the deployment manifest. +HANDLER_L1_ROLLUP_DEPLOY_BLOCK = 1 CHALLENGE_HANDLER_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" SHADOW_PROVING = true # challenger CHALLENGER_L1_RPC = "http://localhost:8545" CHALLENGER_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" +CHALLENGER_L1_ROLLUP_DEPLOY_BLOCK = 1 CHALLENGER_PRIVATEKEY = "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" diff --git a/prover/bin/challenge/src/abi/Rollup.json b/prover/bin/challenge/src/abi/Rollup.json index 28f7a5c6d..e9da0e250 100644 --- a/prover/bin/challenge/src/abi/Rollup.json +++ b/prover/bin/challenge/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -942,6 +1100,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "pendingBatchCount", + "outputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proofRewardPercent", @@ -968,6 +1145,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1245,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1271,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1336,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/prover/bin/challenge/src/abi/Submitter.json b/prover/bin/challenge/src/abi/Submitter.json new file mode 100644 index 000000000..85eeb4d97 --- /dev/null +++ b/prover/bin/challenge/src/abi/Submitter.json @@ -0,0 +1,660 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "ChallengeDepositUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "CreditClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "MinimumStakeUpdated", + "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": false, + "internalType": "uint256", + "name": "oldValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "RewardPercentageUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SlashRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "Slashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "total", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "SubmitterAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "SubmitterRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalCredit", + "type": "uint256" + } + ], + "name": "WithdrawalCredited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "WithdrawalPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "submitter", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "WithdrawalRequested", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "addSubmitter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "challengeDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimCredit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimSlashRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "claimable", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "exiting", + "outputs": [ + { + "internalType": "bool", + "name": "isExiting", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + }, + { + "internalType": "address", + "name": "rollupContract_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minimumStake_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "challengeDeposit_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardPercentage_", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "isActive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "registered", + "outputs": [ + { + "internalType": "bool", + "name": "isRegistered", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "removeSubmitter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "setMinimumStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "slash", + "outputs": [ + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stake", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "updateChallengeDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index 5e88bf9fa..b62b8e5cc 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -7,3 +7,13 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } + +pub mod pre_submitter_rollup_abi { + use ethers::prelude::abigen; + abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); +} + +pub mod submitter_abi { + use ethers::prelude::abigen; + abigen!(Submitter, "src/abi/Submitter.json"); +} diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index 5c100b9f4..e7f06fe62 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -1,4 +1,6 @@ -use challenge_handler::abi::rollup_abi::Rollup; +use challenge_handler::abi::{rollup_abi::Rollup, submitter_abi::Submitter}; +use challenge_handler::rollup_compat::resolve_canonical_commit; +use challenge_handler::util::read_parse_env; use dotenv::dotenv; use env_logger::Env; use ethers::prelude::*; @@ -39,6 +41,7 @@ pub async fn challenge() -> Result<(), Box> { let l1_rpc = var("CHALLENGER_L1_RPC").expect("Cannot detect L1_RPC env var"); let l1_rollup_address = var("CHALLENGER_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let private_key = var("CHALLENGER_PRIVATEKEY").expect("Cannot detect CHALLENGER_PRIVATEKEY env var"); + let rollup_deployed_block: u64 = read_parse_env("CHALLENGER_L1_ROLLUP_DEPLOY_BLOCK"); let l1_provider: Provider = Provider::::try_from(l1_rpc)?; let l1_signer = Arc::new(SignerMiddleware::new( l1_provider.clone(), @@ -66,21 +69,28 @@ pub async fn challenge() -> Result<(), Box> { let proof_window = l1_rollup.proof_window().await?; log::info!("finalization_period: {:#?} proof_window: {:#?}", finalization_period, proof_window); - let min_deposit: U256 = U256::from(4 * 10u128.pow(18)); - log::info!("min_deposit: {:#?}", min_deposit); - loop { - std::thread::sleep(Duration::from_secs(12)); - let _ = auto_challenge(&l1_provider, &l1_rollup, min_deposit).await; + tokio::time::sleep(Duration::from_secs(12)).await; + let _ = auto_challenge(&l1_provider, &l1_rollup, rollup_deployed_block).await; } } -async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, min_deposit: U256) -> Result<(), Box> { +async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, rollup_deployed_block: u64) -> Result<(), Box> { // Search for the latest batch. - let latest = match l1_provider.get_block_number().await { - Ok(bn) => bn, + let (latest, snapshot_hash) = match l1_provider.get_block(BlockNumber::Finalized).await { + Ok(Some(block)) => match (block.number, block.hash) { + (Some(number), Some(hash)) => (number, hash), + _ => { + log::error!("finalized L1 block has no stable identity"); + return Ok(()); + } + }, + Ok(None) => { + log::error!("finalized L1 block is unavailable"); + return Ok(()); + } Err(e) => { - log::error!("L1 provider.get_block_number error: {:#?}", e); + log::error!("L1 provider.get finalized block error: {:#?}", e); return Ok(()); } }; @@ -101,44 +111,28 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi } log::info!("latest blocknum = {:#?}", latest); - let start = if latest > U64::from(600) { - latest - U64::from(600) - } else { - U64::from(1) - }; - - let filter = l1_rollup.commit_batch_filter().filter.from_block(start).address(l1_rollup.address()); - let mut logs: Vec = match l1_provider.get_logs(&filter).await { - Ok(logs) => logs, - Err(e) => { - log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); - return Ok(()); - } - }; - - if logs.is_empty() { - log::error!("There have been no commit_batch logs for the last 600 blocks."); + let block_id = BlockId::Number(BlockNumber::Number(latest)); + let submitter_address = l1_rollup.submitter_contract().block(block_id).call().await?; + let submitter = Submitter::new(submitter_address, l1_rollup.client()); + let min_deposit = submitter.challenge_deposit().block(block_id).call().await?; + let batch_index = l1_rollup.last_committed_batch_index().block(block_id).call().await?.as_u64(); + if resolve_canonical_commit(l1_rollup, l1_provider, batch_index, rollup_deployed_block, latest) + .await? + .is_none() + { + log::warn!("latest batch {batch_index} has no canonical Commit at fixed snapshot"); return Ok(()); } - - logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); - let batch_index = match logs.get(logs.len() - 2) { - Some(log) => log.topics[1].to_low_u64_be(), - None => { - log::error!("find commit_batch log error"); - return Ok(()); - } - }; log::info!("latest batch index = {:#?}", batch_index); // Challenge state. - let is_batch_finalized = l1_rollup.is_batch_finalized(U256::from(batch_index)).await?; + let is_batch_finalized = l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await?; if is_batch_finalized { log::info!("is_batch_finalized = true, No need for challenge, batch index = {:#?}", batch_index); return Ok(()); } - let challenges = match l1_rollup.challenges(U256::from(batch_index)).await { + let challenges = match l1_rollup.challenges(U256::from(batch_index)).block(block_id).call().await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.challenges error, batch index = {:#?}, {:#?}", batch_index, e); @@ -151,7 +145,11 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi return Ok(()); } - let batch_hash = l1_rollup.committed_batches(U256::from(batch_index)).await?; + let batch_hash = l1_rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?; + if !snapshot_unchanged(l1_provider, latest, snapshot_hash).await { + log::error!("finalized L1 snapshot changed while preparing auto-challenge"); + return Ok(()); + } // l1_rollup.connect() let tx: FunctionCall<_, _, _> = l1_rollup.challenge_state(batch_index, batch_hash).value(min_deposit); @@ -210,7 +208,13 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr } else { U64::from(1) }; - let filter = l1_rollup.challenge_state_filter().filter.from_block(start).address(l1_rollup.address()); + let block_id = BlockId::Number(BlockNumber::Number(latest)); + let filter = l1_rollup + .challenge_state_filter() + .filter + .from_block(start) + .to_block(latest) + .address(l1_rollup.address()); let mut logs: Vec = match l1_provider.get_logs(&filter).await { Ok(logs) => logs, Err(e) => { @@ -227,16 +231,22 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr for log in logs { let batch_index: u64 = log.topics[1].to_low_u64_be(); - let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).await { + let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).block(block_id).call().await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.batch_in_challenge error, batch index = {:#?}, {:#?}", batch_index, e); return None; } }; - let _is_batch_finalized: bool = l1_rollup.is_batch_finalized(U256::from(batch_index)).await.unwrap(); + let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await { + Ok(value) => value, + Err(err) => { + log::error!("query l1_rollup.is_batch_finalized failed: {err:#}"); + return None; + } + }; - if batch_in_challenge { + if batch_in_challenge && !is_batch_finalized { log::info!("prev challenge not finalized, batch index = {:#?}", batch_index); return Some(true); } @@ -246,6 +256,13 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr Some(false) } +async fn snapshot_unchanged(provider: &Provider, number: U64, expected_hash: H256) -> bool { + matches!( + provider.get_block(number).await, + Ok(Some(block)) if block.hash == Some(expected_hash) + ) +} + // Check layer2 state. async fn verify_state_transition() { // Do nothing diff --git a/prover/bin/challenge/src/external_sign.rs b/prover/bin/challenge/src/external_sign.rs index fb4a28fa2..627de3b08 100644 --- a/prover/bin/challenge/src/external_sign.rs +++ b/prover/bin/challenge/src/external_sign.rs @@ -97,7 +97,6 @@ impl ExternalSign { return Err("ext_sign response sign data invalid".into()); } - let sig = hex::decode(&response.result.sign_datas[0].sign[2..])?; let signed_tx: Bytes = tx.rlp_signed(&Signature::try_from(sig.as_slice())?); Ok(signed_tx) @@ -141,7 +140,7 @@ impl ExternalSign { log::debug!("===payload: {:?}", serde_json::to_string(payload).unwrap()); let response: reqwest::Response = self.client.post(url).json(&payload).send().await?; log::info!("===do_request response: {:?}", response); - + let status = response.status(); if !status.is_success() { let text = response.text().await?; diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 36eac035f..c949799ed 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,13 +1,14 @@ -use crate::abi::rollup_abi::{CommitBatchCall, Rollup}; +use crate::abi::{rollup_abi::Rollup, submitter_abi::Submitter}; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; +use crate::rollup_compat::{decode_batch_data_input, resolve_canonical_commit, CanonicalCommit}; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; +use ethers::prelude::*; use ethers::providers::{Http, Provider}; use ethers::signers::Wallet; use ethers::types::Address; use ethers::types::Bytes; -use ethers::{abi::AbiDecode, prelude::*}; use eyre::anyhow; use serde::{Deserialize, Serialize}; use std::env::var; @@ -51,6 +52,7 @@ pub struct ChallengeHandler { l1_provider: Provider, l2_rpc: String, ext_signer: Option, + rollup_deployed_block: u64, } impl ChallengeHandler { @@ -60,6 +62,7 @@ impl ChallengeHandler { let l2_rpc = var("HANDLER_L2_RPC").expect("Cannot detect L2_RPC env var"); let l1_rollup_address = var("HANDLER_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let _ = var("HANDLER_PROVER_RPC").expect("Cannot detect PROVER_RPC env var"); + let rollup_deployed_block: u64 = read_parse_env("HANDLER_L1_ROLLUP_DEPLOY_BLOCK"); let private_key = read_env_var( "CHALLENGE_HANDLER_PRIVATE_KEY", @@ -98,6 +101,7 @@ impl ChallengeHandler { l1_provider, l2_rpc, ext_signer, + rollup_deployed_block, } } @@ -109,11 +113,36 @@ impl ChallengeHandler { loop { sleep(Duration::from_secs(12)).await; + // A challenge win/slash does not terminate the batch. Keep the + // service in an explicit pending state until the owner executes + // the canonical RevertBatch and clears revertReqIndex. + match l1_rollup.revert_req_index().await { + Ok(index) if !index.is_zero() => { + log::warn!("challenge result is awaiting owner RevertBatch, revert_req_index={}", index); + continue; + } + Ok(_) => {} + Err(err) => { + log::error!("query revertReqIndex failed: {err:#}"); + continue; + } + } + // Step1. fetch latest blocknum. - let latest = match l1_provider.get_block_number().await { - Ok(bn) => bn, + let (latest, snapshot_hash) = match l1_provider.get_block(BlockNumber::Finalized).await { + Ok(Some(block)) => match (block.number, block.hash) { + (Some(number), Some(hash)) => (number, hash), + _ => { + log::error!("finalized L1 block has no stable identity"); + continue; + } + }, + Ok(None) => { + log::error!("finalized L1 block is unavailable"); + continue; + } Err(e) => { - log::error!("L1 provider.get_block_number error: {:#?}", e); + log::error!("L1 provider.get finalized block error: {:#?}", e); continue; } }; @@ -146,12 +175,13 @@ impl ChallengeHandler { METRICS.detected_batch_index.set(batch_index as i64); // Step3. query challenged batch info. - let (challenged_rollup_hash, batch_hash) = match query_batch_tx(latest, l1_rollup, batch_index, l1_provider).await { + let (challenged_commit, batch_hash) = match query_batch_tx(latest, l1_rollup, batch_index, self.rollup_deployed_block, l1_provider).await + { Some(value) => value, None => continue, }; - let mut batch_info = match batch_inspect(l1_rollup, l1_provider, batch_index, challenged_rollup_hash).await { + let mut batch_info = match batch_inspect(l1_rollup, l1_provider, batch_index, &challenged_commit, latest).await { Some(mut b) => { b.batch_index = batch_index; b.parent_batch_hash = batch_hash.as_bytes().try_into().unwrap_or_default(); @@ -159,6 +189,10 @@ impl ChallengeHandler { } None => continue, }; + if !snapshot_unchanged(l1_provider, latest, snapshot_hash).await { + log::error!("finalized L1 snapshot changed while building challenge proof input"); + continue; + } let blocks_len = batch_info.end_block - batch_info.start_block + 1; log::info!( @@ -241,8 +275,18 @@ impl ChallengeHandler { } async fn prove_state(&self, batch_index: u64, batch_header: Bytes, batch_proof: ProveResult, l1_rollup: &RollupType) -> bool { + let signer = if let Some(external) = &self.ext_signer { + Address::from_str(&external.address).unwrap_or_default() + } else { + l1_rollup.client().address() + }; for _ in 0..MAX_RETRY_TIMES { sleep(Duration::from_secs(12)).await; + if !self.proof_signer_is_active(l1_rollup, signer).await { + // Re-run the gate before every retry: a threshold increase, + // exit, or slash between attempts must stop transmission. + return false; + } log::info!("starting prove state onchain, batch index = {:#?}", batch_index); let proof = Bytes::from(batch_proof.proof_data.clone()); @@ -263,6 +307,50 @@ impl ChallengeHandler { } false } + + async fn proof_signer_is_active(&self, l1_rollup: &RollupType, signer: Address) -> bool { + let (number, hash) = match self.l1_provider.get_block(BlockNumber::Finalized).await { + Ok(Some(block)) => match (block.number, block.hash) { + (Some(number), Some(hash)) => (number, hash), + _ => { + log::error!("finalized L1 block has no stable identity"); + return false; + } + }, + Ok(None) => { + log::error!("finalized L1 block is unavailable"); + return false; + } + Err(err) => { + log::error!("query finalized L1 snapshot failed: {err:#}"); + return false; + } + }; + let snapshot = BlockId::Number(BlockNumber::Number(number)); + let submitter_address = match l1_rollup.submitter_contract().block(snapshot).call().await { + Ok(address) => address, + Err(err) => { + log::error!("query Rollup.submitterContract failed: {err:#}"); + return false; + } + }; + let submitter = Submitter::new(submitter_address, l1_rollup.client()); + let active = match submitter.is_active(signer).block(snapshot).call().await { + Ok(active) => active, + Err(err) => { + log::error!("Submitter.isActive preflight failed: {err:#}"); + return false; + } + }; + if !snapshot_unchanged(&self.l1_provider, number, hash).await { + log::error!("finalized snapshot changed during Submitter.isActive preflight"); + return false; + } + if !active { + log::error!("refusing proveState from inactive submitter signer {signer:?}"); + } + active + } } /** @@ -292,65 +380,35 @@ async fn query_proof(batch_index: u64) -> Option { Some(prove_result) } -async fn query_batch_tx(latest: U64, l1_rollup: &RollupType, batch_index: u64, l1_provider: &Provider) -> Option<(H256, H256)> { - let start = if latest > U64::from(7200 * 3) { - // Depends on challenge period - latest - U64::from(7200 * 3) - } else { - U64::from(1) +async fn query_batch_tx( + latest: U64, + l1_rollup: &RollupType, + batch_index: u64, + rollup_deployed_block: u64, + l1_provider: &Provider, +) -> Option<(CanonicalCommit, H256)> { + let commit = match resolve_canonical_commit(l1_rollup, l1_provider, batch_index, rollup_deployed_block, latest).await { + Ok(Some(commit)) => commit, + Ok(None) => { + log::warn!("batch {batch_index} has no canonical Commit at snapshot {latest}"); + return None; + } + Err(err) => { + log::error!("canonical Commit resolution failed: {err:#}"); + return None; + } }; - let challenged_hash = query_tx_hash(l1_rollup, start, batch_index, l1_provider).await.or_else(|| { - log::warn!("challenged_hash is none"); - None - })?; - - let batch_hash: [u8; 32] = l1_rollup.committed_batches(U256::from(batch_index - 1)).await.unwrap_or_default(); - Some((challenged_hash, H256::from_slice(&batch_hash))) -} - -async fn query_tx_hash(l1_rollup: &RollupType, start: U64, batch_index: u64, l1_provider: &Provider) -> Option { - let filter = l1_rollup - .commit_batch_filter() - .filter - .from_block(start) - .topic1(U256::from(batch_index)) - .address(l1_rollup.address()); - let logs: Vec = match l1_provider.get_logs(&filter).await { - Ok(logs) => logs, - Err(e) => { - log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); + let block_id = BlockId::Number(BlockNumber::Number(latest)); + let parent_index = batch_index.checked_sub(1)?; + let parent_hash: [u8; 32] = match l1_rollup.committed_batches(U256::from(parent_index)).block(block_id).call().await { + Ok(hash) => hash, + Err(err) => { + log::error!("query canonical parent batch hash failed: {err:#}"); return None; } }; - if logs.is_empty() { - log::error!("no commit_batch log of {:?}, commit_batch logs is empty", batch_index); - return None; - } - for log in logs { - if log.topics[1].to_low_u64_be() != batch_index { - continue; - } - let tx_hash = log.transaction_hash.unwrap(); - let receipt = l1_provider.get_transaction_receipt(tx_hash).await.unwrap(); - match receipt { - Some(tr) => { - match tr.status.unwrap_or_default().as_u64() { - 1 => return Some(tx_hash), - _ => { - log::warn!("commit_batch receipt is fail: {:#?}", tr); - continue; - } - }; - } - None => { - log::warn!("no commit_batch receipt, batch index = {:?}, tx_hash = {:?}", batch_index, tx_hash); - } - } - } - log::error!("unable to find valid commit_batch log, batch index = {:?}", batch_index); - - None + Some((commit, H256::from_slice(&parent_hash))) } async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provider: &Provider) -> Option { @@ -360,7 +418,13 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide } else { U64::from(1) }; - let filter = l1_rollup.challenge_state_filter().filter.from_block(start).address(l1_rollup.address()); + let block_id = BlockId::Number(BlockNumber::Number(latest)); + let filter = l1_rollup + .challenge_state_filter() + .filter + .from_block(start) + .to_block(latest) + .address(l1_rollup.address()); let mut logs: Vec = match l1_provider.get_logs(&filter).await { Ok(logs) => logs, Err(e) => { @@ -381,14 +445,14 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide for log in logs { let batch_index: u64 = log.topics[1].to_low_u64_be(); - let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).await { + let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).block(block_id).call().await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.batch_in_challenge error, batch index = {:#?}, {:#?}", batch_index, e); return None; } }; - let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).await { + let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.is_batch_finalized error, batch index = {:#?}, {:#?}", batch_index, e); @@ -421,8 +485,15 @@ struct BatchInfo { parent_batch_hash: [u8; 32], } -async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, batch_index: u64, hash: TxHash) -> Option { - let prev_batch_last_bn: U256 = match l1_rollup.batch_data_store(U256::from(batch_index - 1)).await { +async fn batch_inspect( + l1_rollup: &RollupType, + l1_provider: &Provider, + batch_index: u64, + commit: &CanonicalCommit, + snapshot: U64, +) -> Option { + let block_id = BlockId::Number(BlockNumber::Number(snapshot)); + let prev_batch_last_bn: U256 = match l1_rollup.batch_data_store(U256::from(batch_index - 1)).block(block_id).call().await { Ok(s) => s.2, Err(e) => { log::error!("l1_rollup.batch_data_store err: {:#?}", e); @@ -430,7 +501,7 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat } }; //Step1. Get transaction - let result = l1_provider.get_transaction(hash).await; + let result = l1_provider.get_transaction(commit.transaction_hash).await; let tx = match result { Ok(Some(tx)) => tx, Ok(None) => { @@ -442,26 +513,35 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat return None; } }; + if tx.to != Some(l1_rollup.address()) + || tx.block_number != Some(commit.identity.block_number.into()) + || tx.block_hash != Some(commit.block_hash) + || tx.transaction_index != Some(commit.identity.transaction_index.into()) + { + log::error!("canonical Commit transaction identity changed"); + return None; + } //Step2. Parse transaction data let data = tx.input; if data.is_empty() { - log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); + log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", commit.transaction_hash); return None; } - let param = if let Ok(_param) = CommitBatchCall::decode(&data) { - _param - } else { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); - return None; + let param = match decode_batch_data_input(&data) { + Ok(param) => param, + Err(err) => { + log::error!("batch inspect: decode tx.input error, tx_hash = {:?}: {err:#}", commit.transaction_hash); + return None; + } }; - let version: u8 = param.batch_data_input.version; - let prev_state_root: [u8; 32] = param.batch_data_input.prev_state_root; - let post_state_root: [u8; 32] = param.batch_data_input.post_state_root; - let withdrawal_root: [u8; 32] = param.batch_data_input.withdrawal_root; - let last_block_number: u64 = param.batch_data_input.last_block_number; - let num_l1_messages = param.batch_data_input.num_l1_messages; + let version = param.version; + let prev_state_root = param.prev_state_root; + let post_state_root = param.post_state_root; + let withdrawal_root = param.withdrawal_root; + let last_block_number = param.last_block_number; + let num_l1_messages = param.num_l1_messages; log::info!("======> batch inspect: decode tx.input, version = {:#?}", version); log::info!("======> batch inspect: decode tx.input, param = {:#?}", param); @@ -477,7 +557,7 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat }; // prev_batch_header - let prev_batch_header: Bytes = param.batch_data_input.parent_batch_header; + let prev_batch_header = param.parent_batch_header; let prev_total_l1_message = prev_batch_header.get(17..25).unwrap_or_default(); let post_total_l1_message = u64::from_be_bytes(prev_total_l1_message.try_into().unwrap()) + batch_info.l1_message_popped; batch_info.total_l1_message_popped = post_total_l1_message; @@ -485,6 +565,13 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat Some(batch_info) } +async fn snapshot_unchanged(provider: &Provider, number: U64, expected_hash: H256) -> bool { + matches!( + provider.get_block(number).await, + Ok(Some(block)) if block.hash == Some(expected_hash) + ) +} + impl BatchInfo { fn fill_ext(&mut self, batch_header_ex: Vec) -> &Self { log::debug!("batch_header_ex len: {:#?}", batch_header_ex.len()); @@ -580,4 +667,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:?}", e) }; error_msg -} \ No newline at end of file +} diff --git a/prover/bin/challenge/src/lib.rs b/prover/bin/challenge/src/lib.rs index 92477d8b2..d5001864c 100644 --- a/prover/bin/challenge/src/lib.rs +++ b/prover/bin/challenge/src/lib.rs @@ -1,6 +1,6 @@ pub mod abi; +mod external_sign; pub mod handler; pub mod metrics; +pub mod rollup_compat; pub mod util; -mod external_sign; - diff --git a/prover/bin/challenge/src/rollup_compat.rs b/prover/bin/challenge/src/rollup_compat.rs new file mode 100644 index 000000000..a55432706 --- /dev/null +++ b/prover/bin/challenge/src/rollup_compat.rs @@ -0,0 +1,253 @@ +use ethers::{ + abi::AbiDecode, + providers::Middleware, + types::{BlockId, BlockNumber, Bytes, Filter, Log, TxHash, H256, U256, U64}, + utils::keccak256, +}; +use eyre::{eyre, Result}; + +use crate::abi::{ + pre_submitter_rollup_abi::{ + CommitBatchCall as PreSubmitterCommitBatchCall, CommitBatchWithProofCall as PreSubmitterCommitBatchWithProofCall, + CommitStateCall as PreSubmitterCommitStateCall, + }, + rollup_abi::{CommitBatchCall, CommitBatchWithProofCall, CommitStateCall, Rollup}, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SubmissionKind { + CommitBatch, + CommitState, + CommitBatchWithProof, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BatchDataInput { + pub version: u8, + pub parent_batch_header: Bytes, + pub last_block_number: u64, + pub num_l1_messages: u16, + pub prev_state_root: [u8; 32], + pub post_state_root: [u8; 32], + pub withdrawal_root: [u8; 32], + pub kind: SubmissionKind, + pub pre_submitter: bool, +} + +macro_rules! decoded { + ($input:expr, $kind:expr, $pre:expr) => {{ + let input = $input; + BatchDataInput { + version: input.version, + parent_batch_header: input.parent_batch_header, + last_block_number: input.last_block_number, + num_l1_messages: input.num_l1_messages, + prev_state_root: input.prev_state_root, + post_state_root: input.post_state_root, + withdrawal_root: input.withdrawal_root, + kind: $kind, + pre_submitter: $pre, + } + }}; +} + +pub fn decode_batch_data_input(data: &[u8]) -> Result { + if data.len() < 4 { + return Err(eyre!("rollup calldata is shorter than a selector")); + } + + if let Ok(call) = CommitBatchCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, false)); + } + if let Ok(call) = CommitStateCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, false)); + } + if let Ok(call) = CommitBatchWithProofCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, false)); + } + + if let Ok(call) = PreSubmitterCommitBatchCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, true)); + } + if let Ok(call) = PreSubmitterCommitStateCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, true)); + } + if let Ok(call) = PreSubmitterCommitBatchWithProofCall::decode(data) { + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, true)); + } + + Err(eyre!("unsupported rollup submission selector")) +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct LogIdentity { + pub block_number: u64, + pub transaction_index: u64, + pub log_index: u64, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CanonicalCommit { + pub identity: LogIdentity, + pub transaction_hash: TxHash, + pub block_hash: H256, + pub batch_hash: H256, +} + +fn identity(log: &Log) -> Option { + Some(LogIdentity { + block_number: log.block_number?.as_u64(), + transaction_index: log.transaction_index?.as_u64(), + log_index: log.log_index?.as_u64(), + }) +} + +pub fn select_canonical_commit(commits: &[Log], reverts: &[Log], canonical_hash: H256) -> Option { + if canonical_hash.is_zero() { + return None; + } + let last_revert = reverts.iter().filter(|log| !log.removed.unwrap_or_default()).filter_map(identity).max(); + + commits + .iter() + .filter(|log| !log.removed.unwrap_or_default()) + .filter_map(|log| { + let identity = identity(log)?; + if last_revert.is_some_and(|revert| identity <= revert) { + return None; + } + if log.topics.len() < 3 || log.topics[2] != canonical_hash { + return None; + } + Some(CanonicalCommit { + identity, + transaction_hash: log.transaction_hash?, + block_hash: log.block_hash?, + batch_hash: log.topics[2], + }) + }) + .max_by_key(|commit| commit.identity) +} + +const QUERY_RANGE: u64 = 10_000; + +pub async fn resolve_canonical_commit( + rollup: &Rollup, + provider: &P, + batch_index: u64, + rollup_deployed_block: u64, + snapshot_number: U64, +) -> Result> +where + M: Middleware + 'static, + P: Middleware + 'static, +{ + if rollup_deployed_block == 0 || rollup_deployed_block > snapshot_number.as_u64() { + return Err(eyre!( + "invalid Rollup deployment block {rollup_deployed_block} for snapshot {snapshot_number}" + )); + } + let before = provider + .get_block(snapshot_number) + .await? + .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; + let before_hash = before.hash.ok_or_else(|| eyre!("snapshot block has no hash"))?; + let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); + let canonical_hash: H256 = rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?.into(); + if canonical_hash.is_zero() { + return Ok(None); + } + + let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); + let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); + let mut commits = Vec::new(); + let mut reverts = Vec::new(); + let mut from = rollup_deployed_block; + while from <= snapshot_number.as_u64() { + let to = from.saturating_add(QUERY_RANGE - 1).min(snapshot_number.as_u64()); + let base = Filter::new() + .address(rollup.address()) + .from_block(from) + .to_block(to) + .topic1(U256::from(batch_index)); + commits.extend(provider.get_logs(&base.clone().topic0(commit_topic)).await?); + reverts.extend(provider.get_logs(&base.topic0(revert_topic)).await?); + if to == snapshot_number.as_u64() { + break; + } + from = to + 1; + } + + let after = provider + .get_block(snapshot_number) + .await? + .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; + if after.hash != Some(before_hash) { + return Err(eyre!("snapshot block hash changed during canonical resolution")); + } + + Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn log(block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { + Log { + block_number: Some(block.into()), + transaction_index: Some(tx.into()), + log_index: Some(index.into()), + transaction_hash: Some(H256::from_low_u64_be(marker)), + block_hash: Some(H256::from_low_u64_be(block)), + topics: vec![H256::zero(), H256::from_low_u64_be(7), hash], + ..Default::default() + } + } + + #[test] + fn rejects_short_and_unknown_calldata() { + assert!(decode_batch_data_input(&[]).is_err()); + assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + } + + #[test] + fn decodes_shared_pre_and_post_submitter_fixtures() { + let corpus: serde_json::Value = + serde_json::from_str(include_str!("../../../../node/derivation/testdata/rollup_calldata_fixtures.json")).unwrap(); + let mut decoded_count = 0; + for fixture in corpus["fixtures"].as_array().unwrap() { + let epoch = fixture["epoch"].as_str().unwrap(); + if epoch != "pre-submitter" && epoch != "current" { + continue; + } + let data = ethers::utils::hex::decode(fixture["data"].as_str().unwrap().trim_start_matches("0x")).unwrap(); + let decoded = decode_batch_data_input(&data).unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); + assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); + assert_eq!(decoded.last_block_number, fixture["expected"]["lastBlockNumber"].as_u64().unwrap()); + decoded_count += 1; + } + assert_eq!(decoded_count, 6); + } + + #[test] + fn same_hash_recommit_after_revert_is_selected_by_identity() { + let hash = H256::from_low_u64_be(99); + let resolved = select_canonical_commit(&[log(10, 0, 0, hash, 1), log(12, 0, 0, hash, 3)], &[log(11, 0, 0, hash, 2)], hash).unwrap(); + assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); + } + + #[test] + fn zero_hash_and_same_block_revert_order_fail_closed() { + let hash = H256::from_low_u64_be(99); + assert!(select_canonical_commit(&[log(10, 0, 0, hash, 1)], &[], H256::zero()).is_none()); + + let before_revert = log(10, 0, 1, hash, 1); + let revert = log(10, 0, 2, hash, 2); + assert!(select_canonical_commit(&[before_revert], std::slice::from_ref(&revert), hash).is_none()); + + let after_revert = log(10, 0, 3, hash, 3); + let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); + assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); + } +} diff --git a/prover/bin/challenge/src/util.rs b/prover/bin/challenge/src/util.rs index 3cfb7432c..d48aa397f 100644 --- a/prover/bin/challenge/src/util.rs +++ b/prover/bin/challenge/src/util.rs @@ -47,6 +47,7 @@ pub fn read_parse_env(var_name: &'static str) -> T { } #[tokio::test] +#[ignore = "requires HANDLER_PROVER_RPC and an external prover service"] async fn test_call_prover() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); dotenv::dotenv().ok(); diff --git a/prover/bin/shadow-prove/.env.dev b/prover/bin/shadow-prove/.env.dev index 25b52d157..4900af649 100644 --- a/prover/bin/shadow-prove/.env.dev +++ b/prover/bin/shadow-prove/.env.dev @@ -4,7 +4,10 @@ SHADOW_PROVING_L2_RPC = "http://localhost:8545" SHADOW_PROVING_PROVER_RPC ="http://localhost:3030" SHADOW_PROVING_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" SHADOW_PROVING_L1_SHADOW_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" +# Development fixture only. Production must use the archived Rollup proxy +# deployment block from the deployment manifest. +SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK = 1 SHADOW_PROVING_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" SHADOW_PROVING_MAX_TXN = 600 SHADOW_PROVING_MAX_BLOCK = 300 -SHADOW_PROVING_BATCH_INTERVAL = 7200 \ No newline at end of file +SHADOW_PROVING_BATCH_INTERVAL = 7200 diff --git a/prover/bin/shadow-prove/abi/Rollup.json b/prover/bin/shadow-prove/abi/Rollup.json index e32ca8619..e9da0e250 100644 --- a/prover/bin/shadow-prove/abi/Rollup.json +++ b/prover/bin/shadow-prove/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -383,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -460,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -656,28 +694,6 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" } ], "name": "commitBatch", @@ -729,40 +745,68 @@ "name": "batchDataInput", "type": "tuple" }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, { - "internalType": "bytes", - "name": "signature", - "type": "bytes" + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" } ], - "name": "commitBatchWithProof", + "name": "commitState", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -880,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -940,6 +984,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -978,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1056,6 +1100,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "pendingBatchCount", + "outputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proofRewardPercent", @@ -1208,6 +1271,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1322,4 +1398,4 @@ "stateMutability": "payable", "type": "receive" } -] \ No newline at end of file +] diff --git a/prover/bin/shadow-prove/src/abi.rs b/prover/bin/shadow-prove/src/abi.rs index d98d7b99d..17a583a48 100644 --- a/prover/bin/shadow-prove/src/abi.rs +++ b/prover/bin/shadow-prove/src/abi.rs @@ -7,6 +7,16 @@ sol!( "abi/Rollup.json" ); +// Immutable production ABI from immediately before the Submitter cutover. +// Keep it in a namespace of its own because both ABI snapshots contain an +// `IRollup.BatchDataInput` internal type. +pub mod pre_submitter { + use alloy_sol_types::sol; + + sol!(PreSubmitterRollup, "abi/pre_submitter/Rollup.json"); +} +pub use pre_submitter::PreSubmitterRollup; + sol!( #[sol(rpc)] ShadowRollup, diff --git a/prover/bin/shadow-prove/src/execute.rs b/prover/bin/shadow-prove/src/execute.rs index 1a5142e6e..b063b747f 100644 --- a/prover/bin/shadow-prove/src/execute.rs +++ b/prover/bin/shadow-prove/src/execute.rs @@ -124,6 +124,7 @@ mod tests { // cargo test -p shadow-proving --lib -- execute::tests::test_execute_range --exact --nocapture -- --start-block 0x35 --end-block 0x36 --rpc http://127.0.0.1:9545 #[test] + #[ignore = "requires an external L2 RPC and explicit CLI fixture arguments"] fn test_execute_range() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); @@ -138,6 +139,7 @@ mod tests { // cargo test -p shadow-proving --lib -- execute::tests::test_execute_block --exact --nocapture -- --block-number 19997 --rpc http://127.0.0.1:9545 #[tokio::test(flavor = "multi_thread")] + #[ignore = "requires an external L2 RPC and explicit CLI fixture arguments"] async fn test_execute_block() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); @@ -152,6 +154,7 @@ mod tests { } #[tokio::test] + #[ignore = "requires a local L2 RPC fixture"] async fn test_execute_batch() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let handle = tokio::spawn(async move { @@ -171,6 +174,7 @@ mod tests { handle.await.unwrap(); } #[tokio::test] + #[ignore = "requires a local L2 RPC fixture"] async fn test_execute_remote() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let provider = @@ -184,8 +188,10 @@ mod tests { println!("batch_info.post_state_root: {:?}", batch_info.post_state_root); } - // cargo test --package shadow-proving --lib -- execute::tests::test_execute_local --exact --nocapture + // cargo test --package shadow-proving --lib -- execute::tests::test_execute_local --exact + // --nocapture #[tokio::test] + #[ignore = "requires pre-generated local executor fixtures"] async fn test_execute_local() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let dir = "../../testdata/state"; @@ -209,6 +215,7 @@ mod tests { } #[tokio::test] + #[ignore = "requires a production L2 RPC and writes a local fixture"] async fn execute_batch_input() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let provider = ProviderBuilder::new() @@ -259,6 +266,7 @@ mod tests { } #[tokio::test] + #[ignore = "requires a pre-generated local executor fixture"] async fn execute_batch_input_local() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let file = File::open("proof/shadow_input.json").unwrap(); diff --git a/prover/bin/shadow-prove/src/lib.rs b/prover/bin/shadow-prove/src/lib.rs index 62e485968..3766143bf 100644 --- a/prover/bin/shadow-prove/src/lib.rs +++ b/prover/bin/shadow-prove/src/lib.rs @@ -8,6 +8,7 @@ use crate::util::read_env_var; pub mod abi; pub mod execute; pub mod metrics; +pub mod rollup_compat; pub mod shadow_prove; pub mod shadow_rollup; pub mod util; diff --git a/prover/bin/shadow-prove/src/main.rs b/prover/bin/shadow-prove/src/main.rs index a6cf82946..e31d1139b 100644 --- a/prover/bin/shadow-prove/src/main.rs +++ b/prover/bin/shadow-prove/src/main.rs @@ -22,8 +22,10 @@ use shadow_proving::{ SHADOW_PROVING_MAX_TXN, SHADOW_PROVING_PROVER_RPC, }; -use tokio::time::{interval, sleep}; -use tokio::{sync::broadcast, time::MissedTickBehavior}; +use tokio::{ + sync::broadcast, + time::{interval, sleep, MissedTickBehavior}, +}; #[tokio::main] async fn main() { @@ -157,6 +159,7 @@ fn init_shadow_proving( let private_key: String = read_parse_env("SHADOW_PROVING_PRIVATE_KEY"); let rollup: String = read_parse_env("SHADOW_PROVING_L1_ROLLUP"); let shadow_rollup: String = read_parse_env("SHADOW_PROVING_L1_SHADOW_ROLLUP"); + let rollup_deployed_block: u64 = read_parse_env("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK"); let signer: PrivateKeySigner = private_key.parse().expect("parse PrivateKeySigner"); let wallet: EthereumWallet = EthereumWallet::from(signer.clone()); @@ -179,6 +182,7 @@ fn init_shadow_proving( l1_provider.clone(), l2_provider.clone(), l1_signer.clone(), + rollup_deployed_block, ); let shadow_prover = ShadowProver::new( @@ -305,12 +309,14 @@ fn log_format( } #[tokio::test] +#[ignore = "requires the full configured shadow-proving environment"] async fn test_shadow() { dotenv().ok(); env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); log::info!("Starting shadow proving..."); - // cargo test -p shadow-proving --bin shadow-proving -- test_shadow --exact --nocapture -- --batch-num 100 --no-prove + // cargo test -p shadow-proving --bin shadow-proving -- test_shadow --exact --nocapture -- + // --batch-num 100 --no-prove let (batch_num, prove) = test_args::read_shadow_test_args_from_argv(); let (batch_syncer, shadow_prover, l2_provider) = init_shadow_proving(); diff --git a/prover/bin/shadow-prove/src/rollup_compat.rs b/prover/bin/shadow-prove/src/rollup_compat.rs new file mode 100644 index 000000000..5a2fd5a3f --- /dev/null +++ b/prover/bin/shadow-prove/src/rollup_compat.rs @@ -0,0 +1,334 @@ +use alloy_primitives::{Bytes, TxHash, B256, U256}; +use alloy_provider::{DynProvider, Provider}; +use alloy_rpc_types::{BlockId, BlockNumberOrTag, Log}; +use alloy_sol_types::SolCall; +use anyhow::{anyhow, Result}; + +use crate::abi::{ + pre_submitter::IRollup as PreSubmitterIRollup, IRollup, PreSubmitterRollup, Rollup, + Rollup::RollupInstance, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SubmissionKind { + CommitBatch, + CommitState, + CommitBatchWithProof, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BatchDataInput { + pub version: u8, + pub parent_batch_header: Bytes, + pub last_block_number: u64, + pub num_l1_messages: u16, + pub prev_state_root: [u8; 32], + pub post_state_root: [u8; 32], + pub withdrawal_root: [u8; 32], + pub kind: SubmissionKind, + pub pre_submitter: bool, +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct LogIdentity { + pub block_number: u64, + pub transaction_index: u64, + pub log_index: u64, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CanonicalCommit { + pub identity: LogIdentity, + pub transaction_hash: TxHash, + pub block_hash: B256, + pub batch_hash: B256, +} + +fn log_identity(log: &Log) -> Option { + Some(LogIdentity { + block_number: log.block_number?, + transaction_index: log.transaction_index?, + log_index: log.log_index?, + }) +} + +/// Select the last canonical Commit after the last Revert at one fixed L1 +/// snapshot. Full log identity (rather than batch hash alone) deliberately +/// distinguishes a same-hash recommit. +pub fn select_canonical_commit( + commits: &[Log], + reverts: &[Log], + canonical_hash: B256, +) -> Option { + if canonical_hash == B256::ZERO { + return None; + } + + let last_revert = reverts.iter().filter(|log| !log.removed).filter_map(log_identity).max(); + + commits + .iter() + .filter(|log| !log.removed) + .filter_map(|log| { + let identity = log_identity(log)?; + if last_revert.is_some_and(|revert| identity <= revert) { + return None; + } + let topics = log.topics(); + if topics.len() < 3 || topics[2] != canonical_hash { + return None; + } + Some(CanonicalCommit { + identity, + transaction_hash: log.transaction_hash?, + block_hash: log.block_hash?, + batch_hash: topics[2], + }) + }) + .max_by_key(|commit| commit.identity) +} + +const LOG_QUERY_BLOCK_RANGE: u64 = 10_000; + +/// Resolve a batch's canonical Commit using one numbered snapshot. The block +/// hash is checked before and after all getter/log reads so RPCs without +/// EIP-1898 support cannot silently combine different forks. +pub async fn resolve_canonical_commit( + provider: &DynProvider, + rollup: &RollupInstance, + batch_index: u64, + rollup_deployed_block: u64, + snapshot_number: u64, +) -> Result> { + if rollup_deployed_block == 0 || rollup_deployed_block > snapshot_number { + return Err(anyhow!( + "invalid Rollup deployment block {rollup_deployed_block} for snapshot {snapshot_number}" + )); + } + let snapshot_tag = BlockNumberOrTag::Number(snapshot_number); + let before = provider + .get_block_by_number(snapshot_tag) + .await? + .ok_or_else(|| anyhow!("snapshot block {snapshot_number} not found"))?; + let before_hash = before.header.hash; + + let canonical_hash = rollup + .committedBatches(U256::from(batch_index)) + .block(BlockId::Number(snapshot_tag)) + .call() + .await?; + if canonical_hash == B256::ZERO { + return Ok(None); + } + + let mut commits = Vec::new(); + let mut reverts = Vec::new(); + let mut from = rollup_deployed_block; + while from <= snapshot_number { + let to = from.saturating_add(LOG_QUERY_BLOCK_RANGE - 1).min(snapshot_number); + let commit_filter = rollup + .CommitBatch_filter() + .filter + .from_block(from) + .to_block(to) + .topic1(U256::from(batch_index)) + .address(*rollup.address()); + commits.extend(provider.get_logs(&commit_filter).await?); + + let revert_filter = rollup + .RevertBatch_filter() + .filter + .from_block(from) + .to_block(to) + .topic1(U256::from(batch_index)) + .address(*rollup.address()); + reverts.extend(provider.get_logs(&revert_filter).await?); + + if to == snapshot_number { + break; + } + from = to + 1; + } + + let after = provider + .get_block_by_number(snapshot_tag) + .await? + .ok_or_else(|| anyhow!("snapshot block {snapshot_number} disappeared"))?; + if after.header.hash != before_hash { + return Err(anyhow!("snapshot block hash changed during canonical resolution")); + } + + Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) +} + +fn current_input(input: IRollup::BatchDataInput, kind: SubmissionKind) -> BatchDataInput { + BatchDataInput { + version: input.version, + parent_batch_header: input.parentBatchHeader, + last_block_number: input.lastBlockNumber, + num_l1_messages: input.numL1Messages, + prev_state_root: *input.prevStateRoot, + post_state_root: *input.postStateRoot, + withdrawal_root: *input.withdrawalRoot, + kind, + pre_submitter: false, + } +} + +fn historical_input( + input: PreSubmitterIRollup::BatchDataInput, + kind: SubmissionKind, +) -> BatchDataInput { + BatchDataInput { + version: input.version, + parent_batch_header: input.parentBatchHeader, + last_block_number: input.lastBlockNumber, + num_l1_messages: input.numL1Messages, + prev_state_root: *input.prevStateRoot, + post_state_root: *input.postStateRoot, + withdrawal_root: *input.withdrawalRoot, + kind, + pre_submitter: true, + } +} + +/// Decode only the first `BatchDataInput` argument from every submission ABI +/// supported across the Submitter cutover. Unknown and short selectors fail +/// closed; historical signature data is intentionally not exposed. +pub fn decode_batch_data_input(data: &[u8]) -> Result { + if data.len() < 4 { + return Err(anyhow!("rollup calldata is shorter than a selector")); + } + + if let Ok(call) = Rollup::commitBatchCall::abi_decode(data) { + return Ok(current_input(call.batchDataInput, SubmissionKind::CommitBatch)); + } + if let Ok(call) = Rollup::commitStateCall::abi_decode(data) { + return Ok(current_input(call.batchDataInput, SubmissionKind::CommitState)); + } + if let Ok(call) = Rollup::commitBatchWithProofCall::abi_decode(data) { + return Ok(current_input(call.batchDataInput, SubmissionKind::CommitBatchWithProof)); + } + + if let Ok(call) = PreSubmitterRollup::commitBatchCall::abi_decode(data) { + return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitBatch)); + } + if let Ok(call) = PreSubmitterRollup::commitStateCall::abi_decode(data) { + return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitState)); + } + if let Ok(call) = PreSubmitterRollup::commitBatchWithProofCall::abi_decode(data) { + return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitBatchWithProof)); + } + + Err(anyhow!("unsupported rollup submission selector")) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::{Address, Log as PrimitiveLog}; + + fn rpc_log( + batch_index: u64, + batch_hash: B256, + block_number: u64, + transaction_index: u64, + log_index: u64, + tx_marker: u8, + ) -> Log { + Log { + inner: PrimitiveLog::new_unchecked( + Address::ZERO, + vec![ + B256::ZERO, + B256::from(U256::from(batch_index).to_be_bytes::<32>()), + batch_hash, + ], + Bytes::new(), + ), + block_number: Some(block_number), + transaction_index: Some(transaction_index), + log_index: Some(log_index), + transaction_hash: Some(B256::repeat_byte(tx_marker)), + block_hash: Some(B256::repeat_byte(block_number as u8)), + ..Default::default() + } + } + + #[test] + fn rejects_short_and_unknown_calldata() { + assert!(decode_batch_data_input(&[]).is_err()); + assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + } + + #[test] + fn decodes_shared_pre_and_post_submitter_fixtures() { + let corpus: serde_json::Value = serde_json::from_str(include_str!( + "../../../../node/derivation/testdata/rollup_calldata_fixtures.json" + )) + .unwrap(); + let mut decoded_count = 0; + for fixture in corpus["fixtures"].as_array().unwrap() { + let epoch = fixture["epoch"].as_str().unwrap(); + if epoch != "pre-submitter" && epoch != "current" { + continue; + } + let data = alloy_primitives::hex::decode( + fixture["data"].as_str().unwrap().trim_start_matches("0x"), + ) + .unwrap(); + let decoded = decode_batch_data_input(&data) + .unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); + assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); + assert_eq!( + decoded.last_block_number, + fixture["expected"]["lastBlockNumber"].as_u64().unwrap() + ); + decoded_count += 1; + } + assert_eq!(decoded_count, 6); + } + + #[test] + fn selector_sets_are_distinct() { + assert_eq!(Rollup::commitBatchCall::SELECTOR, [0x41, 0xf7, 0x56, 0xda]); + assert_eq!(Rollup::commitStateCall::SELECTOR, [0x67, 0xca, 0xa3, 0x7a]); + assert_eq!(Rollup::commitBatchWithProofCall::SELECTOR, [0x15, 0x44, 0xba, 0x3a]); + + assert_eq!(PreSubmitterRollup::commitBatchCall::SELECTOR, [0x42, 0x88, 0x68, 0xb5]); + assert_eq!(PreSubmitterRollup::commitStateCall::SELECTOR, [0x1e, 0x88, 0x25, 0xbe]); + assert_eq!( + PreSubmitterRollup::commitBatchWithProofCall::SELECTOR, + [0x4e, 0x8f, 0x1d, 0x67] + ); + } + + #[test] + fn recommit_after_revert_wins_even_when_hash_is_identical() { + let hash = B256::repeat_byte(0x44); + let first = rpc_log(7, hash, 10, 0, 0, 1); + let revert = rpc_log(7, hash, 11, 0, 0, 2); + let second = rpc_log(7, hash, 12, 0, 0, 3); + + let resolved = select_canonical_commit(&[first, second], &[revert], hash).unwrap(); + assert_eq!(resolved.transaction_hash, B256::repeat_byte(3)); + assert_eq!(resolved.identity.block_number, 12); + } + + #[test] + fn zero_hash_and_same_block_revert_order_fail_closed() { + let hash = B256::repeat_byte(0x44); + assert!( + select_canonical_commit(&[rpc_log(7, hash, 10, 0, 0, 1)], &[], B256::ZERO).is_none() + ); + + let before_revert = rpc_log(7, hash, 10, 0, 1, 1); + let revert = rpc_log(7, hash, 10, 0, 2, 2); + assert!(select_canonical_commit(&[before_revert], std::slice::from_ref(&revert), hash) + .is_none()); + + let after_revert = rpc_log(7, hash, 10, 0, 3, 3); + let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); + assert_eq!(resolved.transaction_hash, B256::repeat_byte(3)); + } +} diff --git a/prover/bin/shadow-prove/src/shadow_prove.rs b/prover/bin/shadow-prove/src/shadow_prove.rs index ad53a2e76..cd0dee8cd 100644 --- a/prover/bin/shadow-prove/src/shadow_prove.rs +++ b/prover/bin/shadow-prove/src/shadow_prove.rs @@ -39,7 +39,8 @@ mod task_status { pub const PROVED: &str = "Proved"; } -// ShadowProver is responsible for proving the batch state onchain through the shadow rollup contract. +// ShadowProver is responsible for proving the batch state onchain through the shadow rollup +// contract. #[derive(Clone, Debug)] pub struct ShadowProver { shadow_provider: DynProvider, @@ -284,14 +285,24 @@ async fn query_proof(batch_index: u64) -> Option { fn test() { use crate::abi::SP1Verifier; use alloy_json_rpc::ErrorPayload; - // Sample JSON error payload from an Ethereum JSON RPC response. - let json = r#"{"code":3,"message":"execution reverted: ","data":"0x810f00230000000000000000000000000000000000000000000000000000000000000001"}"#; + use alloy_primitives::hex; + use alloy_sol_types::SolError; + + let expected_error = SP1Verifier::WrongVerifierSelector { + received: [0, 0, 0, 1].into(), + expected: [0, 0, 0, 2].into(), + }; + let json = format!( + r#"{{"code":3,"message":"execution reverted: ","data":"{}"}}"#, + hex::encode_prefixed(expected_error.abi_encode()) + ); // Parse the JSON into an `ErrorPayload` struct. - let payload: ErrorPayload = serde_json::from_str(json).unwrap(); + let payload: ErrorPayload = serde_json::from_str(&json).unwrap(); if let Some(s) = payload.as_decoded_error::() { - println!("WrongVerifierSelector - expected: {:?}, received: {:?}", s.expected, s.received); + assert_eq!(s.expected, expected_error.expected); + assert_eq!(s.received, expected_error.received); } else if payload.as_decoded_error::().is_some() { println!("WrongVerifierSelector"); } else { diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index df1f7292c..3aa4f4c55 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -1,15 +1,17 @@ -use crate::{metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; +use crate::{metrics::METRICS, BatchInfo}; use alloy_consensus::Transaction; use alloy_network::{Network, ReceiptResponse}; -use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256, U64}; +use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256}; use alloy_provider::{DynProvider, Provider}; -use alloy_rpc_types::Log; -use alloy_sol_types::SolCall; +use alloy_rpc_types::{BlockId, BlockNumberOrTag}; use anyhow::{anyhow, Context, Result}; use futures::future::join_all; use crate::{ + rollup_compat::{ + decode_batch_data_input, resolve_canonical_commit, BatchDataInput, CanonicalCommit, + }, Rollup::{self, RollupInstance}, ShadowRollup::{self, ShadowRollupInstance}, }; @@ -20,6 +22,7 @@ pub struct BatchSyncer { l2_provider: DynProvider, l1_rollup: RollupInstance, l1_shadow_rollup: ShadowRollupInstance, + rollup_deployed_block: u64, } impl BatchSyncer @@ -27,264 +30,140 @@ where P: Provider + Clone, N: Network, { + async fn finalized_snapshot(&self) -> Result<(u64, B256)> { + let block = self + .l1_provider + .get_block_by_number(BlockNumberOrTag::Finalized) + .await? + .ok_or_else(|| anyhow!("finalized L1 block is unavailable"))?; + Ok((block.header.number, block.header.hash)) + } + + async fn assert_snapshot(&self, number: u64, expected_hash: B256) -> Result<()> { + let block = self + .l1_provider + .get_block_by_number(BlockNumberOrTag::Number(number)) + .await? + .ok_or_else(|| anyhow!("snapshot L1 block {number} is unavailable"))?; + if block.header.hash != expected_hash { + return Err(anyhow!( + "finalized L1 snapshot changed: number={number}, expected={expected_hash:?}, actual={:?}", + block.header.hash + )); + } + Ok(()) + } + pub fn new( rollup_address: Address, shadow_rollup_address: Address, l1_provider: DynProvider, l2_provider: DynProvider, wallet: P, + rollup_deployed_block: u64, ) -> Self { let l1_rollup = Rollup::RollupInstance::new(rollup_address, l1_provider.clone()); let l1_shadow_rollup = ShadowRollup::new(shadow_rollup_address, wallet); - Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup } + Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup, rollup_deployed_block } } // Fetch the latest committed batch from l1-rollup if the batch_index has increased. pub async fn get_latest_batch(&self, batch_index: u64) -> Result> { - let last_committed_batch_index = self.l1_rollup.lastCommittedBatchIndex().call().await?; - if last_committed_batch_index <= batch_index + 1 { + let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; + let last_committed_batch_index = self + .l1_rollup + .lastCommittedBatchIndex() + .block(BlockId::Number(BlockNumberOrTag::Number(snapshot))) + .call() + .await? + .to::(); + self.assert_snapshot(snapshot, snapshot_hash).await?; + if last_committed_batch_index <= batch_index.saturating_add(1) { log::info!( "The current batch_index has not increased, latest_batch_index: {last_committed_batch_index:?}" ); return Ok(None); } - self.get_committed_batch().await + if last_committed_batch_index <= 2 { + return Ok(None); + } + self.get_specified_batch_at(last_committed_batch_index - 1, snapshot, snapshot_hash).await } // Fetch the latest committed batch from l1-rollup. pub async fn get_committed_batch(&self) -> Result> { - let latest = match self.l1_provider.get_block_number().await { - Ok(v) => U64::from(v), - Err(e) => { - log::error!("l1_provider.get_block_number error: {:?}", e); - return Err(anyhow!("l1_provider.get_block_number error")); - } - }; - - log::info!("latest l1 blocknum = {:#?}", latest); - let start = if latest > U64::from(*SHADOW_PROVING_BLOCKS_RANGE) { - latest - U64::from(*SHADOW_PROVING_BLOCKS_RANGE) - } else { - U64::from(1) - }; - let filter = self + let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; + let last_committed = self .l1_rollup - .CommitBatch_filter() - .filter - .from_block(start) - .address(*self.l1_rollup.address()); - let mut logs: Vec = match self.l1_provider.get_logs(&filter).await { - Ok(logs) => logs, - Err(e) => { - log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); - return Err(anyhow!("l1_rollup.commit_batch.get_logs provider error")); - } - }; - if logs.is_empty() { - log::warn!("There have been no commit_batch logs for the last 600 blocks"); - return Ok(None); - } - if logs.len() < 3 { - log::warn!("No enough commit_batch logs for the last 600 blocks"); + .lastCommittedBatchIndex() + .block(BlockId::Number(BlockNumberOrTag::Number(snapshot))) + .call() + .await?; + self.assert_snapshot(snapshot, snapshot_hash).await?; + let last_committed = last_committed.to::(); + if last_committed <= 2 { return Ok(None); } - logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); - - let batch_index_hash = match logs.get(logs.len() - 2) { - Some(log) => { - let _index = U256::from_be_slice(log.topics()[1].as_slice()); - (_index.to::(), log.transaction_hash.unwrap_or_default()) - } - None => { - return Err(anyhow!("find commit_batch log error")); - } - }; - - if batch_index_hash.0 == 0 { - return Err(anyhow!("batch_index is 0")); - } - let prev_tx_hash = match logs.get(logs.len() - 3) { - Some(log) => log.transaction_hash.unwrap_or_default(), - None => { - return Err(anyhow!("find commit_batch log error")); - } - }; - - let (blocks, total_txn_count) = - match self.batch_blocks_inspect(prev_tx_hash, batch_index_hash.1).await { - Some(block_txn) => block_txn, - None => return Err(anyhow!("batch_blocks_inspect none")), - }; - - if blocks.0 >= blocks.1 { - return Err(anyhow!("blocks is empty")); - } - - let batch_info: BatchInfo = BatchInfo { - batch_index: batch_index_hash.0, - start_block: blocks.0, - end_block: blocks.1, - total_txn: total_txn_count, - }; - - // A rollup commit_batch_input contains prev batch_header. - let next_tx_hash = match logs.last() { - Some(log) => log.transaction_hash.unwrap_or_default(), - - None => { - return Err(anyhow!("find commit_batch log error")); - } - }; - let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) - .await - .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; - - log::info!("Found the committed batch, batch index = {:#?}", batch_index_hash.0); - Ok(Some((batch_info, batch_input.0))) + // The next canonical commit carries the target batch header as its + // parentBatchHeader, so prove the newest batch that has a canonical + // successor rather than relying on three adjacent logs. + self.get_specified_batch_at(last_committed - 1, snapshot, snapshot_hash).await } /// Fetch a specified batch from l1-rollup by batch_num. pub async fn get_specified_batch(&self, batch_num: u64) -> Result> { - use std::collections::{HashMap, HashSet}; + let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; + self.get_specified_batch_at(batch_num, snapshot, snapshot_hash).await + } - if batch_num == 0 { - return Err(anyhow!("batch_num is 0")); - } - if batch_num == 1 { + async fn get_specified_batch_at( + &self, + batch_num: u64, + snapshot: u64, + snapshot_hash: B256, + ) -> Result> { + if batch_num <= 1 { // We need prev(batch_num-1) to infer start_block, and next(batch_num+1) to retrieve the // specified batch header (via parentBatchHeader). - return Err(anyhow!("batch_num is 1, cannot infer prev batch")); + return Err(anyhow!("batch_num must be greater than 1")); } - let last_committed_batch_index = self.l1_rollup.lastCommittedBatchIndex().call().await?; - if last_committed_batch_index <= batch_num { - log::info!( - "last committed batch index {:#?} is less than or equal to the specified batch_num {:#?}", - last_committed_batch_index, - batch_num - ); + self.assert_snapshot(snapshot, snapshot_hash).await?; + let prev = resolve_canonical_commit( + &self.l1_provider, + &self.l1_rollup, + batch_num - 1, + self.rollup_deployed_block, + snapshot, + ) + .await?; + self.assert_snapshot(snapshot, snapshot_hash).await?; + let current = resolve_canonical_commit( + &self.l1_provider, + &self.l1_rollup, + batch_num, + self.rollup_deployed_block, + snapshot, + ) + .await?; + self.assert_snapshot(snapshot, snapshot_hash).await?; + let next = resolve_canonical_commit( + &self.l1_provider, + &self.l1_rollup, + batch_num + 1, + self.rollup_deployed_block, + snapshot, + ) + .await?; + self.assert_snapshot(snapshot, snapshot_hash).await?; + let (Some(prev), Some(current), Some(next)) = (prev, current, next) else { return Ok(None); - } - - let latest = match self.l1_provider.get_block_number().await { - Ok(v) => U64::from(v), - Err(e) => { - log::error!("l1_provider.get_block_number error: {:?}", e); - return Err(anyhow!("l1_provider.get_block_number error")); - } }; - log::info!("latest l1 blocknum = {:#?}", latest); - - // Goal: collect (batch_index, tx_hash) for the specified batch and its immediate neighbors. - // - prev: batch_num - 1 (used to infer start_block) - // - curr: batch_num (used to infer end_block) - // - next: batch_num + 1 (commitBatch calldata contains parentBatchHeader == curr header) - let targets: HashSet = [batch_num - 1, batch_num, batch_num + 1].into_iter().collect(); - let mut found: HashMap = HashMap::with_capacity(3); - - let blocks_window = 600u64; - let mut distance_count = 1u64; - loop { - if distance_count > 100 { - return Err(anyhow!( - "Exceeded max distance count when searching commit_batch logs" - )); - } - // Scan backward from `latest` in fixed-size windows until all 3 targets are found. - // Note: alloy filter block numbers are U64; avoid underflow. - let to_block = latest.saturating_sub(U64::from(blocks_window * (distance_count - 1))); - let mut from_block = latest.saturating_sub(U64::from(blocks_window * distance_count)); - if from_block < U64::from(1) { - from_block = U64::from(1); - } - - let filter = self - .l1_rollup - .CommitBatch_filter() - .filter - .from_block(from_block) - .to_block(to_block) - .address(*self.l1_rollup.address()); - - let mut logs: Vec = match self.l1_provider.get_logs(&filter).await { - Ok(logs) => logs, - Err(e) => { - log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); - return Err(anyhow!("l1_rollup.commit_batch.get_logs provider error")); - } - }; - if logs.is_empty() { - log::warn!( - "There have been no commit_batch logs for the this {} blocks window (from={:?}, to={:?})", - blocks_window, - from_block, - to_block - ); - } - - logs.sort_by(|a, b| { - a.block_number.unwrap_or_default().cmp(&b.block_number.unwrap_or_default()) - }); - - for log in logs.iter() { - if found.len() == targets.len() { - break; - } - if log.topics().len() < 2 { - continue; - } - let index_u256 = U256::from_be_slice(log.topics()[1].as_slice()); - let idx = index_u256.to::(); - if !targets.contains(&idx) { - continue; - } - // A given batch_index should appear only once; if duplicated events exist, keep the - // first-seen tx_hash. - found.entry(idx).or_insert(log.transaction_hash.unwrap_or_default()); - } - - if found.len() == targets.len() { - break; - } - - // Reached the chain head (block 1) and still not enough logs found. - if from_block == U64::from(1) { - log::warn!( - "Cannot find enough commit_batch logs for batch_num={} (found={:?})", - batch_num, - found.keys().collect::>() - ); - return Ok(None); - } - - distance_count += 1; - } - - // Assemble the triplet in order: prev, curr, next. - let mut batch_index_hash: Vec<(u64, TxHash)> = Vec::with_capacity(3); - for idx in [batch_num - 1, batch_num, batch_num + 1] { - let tx = *found.get(&idx).unwrap_or(&TxHash::ZERO); - if tx == TxHash::ZERO { - return Ok(None); - } - batch_index_hash.push((idx, tx)); - } - - let prev_tx_hash = batch_index_hash[0].1; - let curr_tx_hash = batch_index_hash[1].1; - let next_tx_hash = batch_index_hash[2].1; - - let (blocks, total_txn_count) = - match self.batch_blocks_inspect(prev_tx_hash, curr_tx_hash).await { - Some(block_txn) => block_txn, - None => return Err(anyhow!("batch_blocks_inspect none")), - }; - if blocks.0 >= blocks.1 { - return Err(anyhow!("blocks is empty")); - } + let ((blocks, total_txn_count), current_input) = + self.batch_blocks_inspect(&prev, ¤t).await?; let batch_info: BatchInfo = BatchInfo { batch_index: batch_num, @@ -294,12 +173,34 @@ where }; // next(batch_num+1) commitBatch calldata contains curr(batch_num) parentBatchHeader. - let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) - .await - .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; + let next_input = + canonical_batch_input_inspect(&self.l1_provider, &next, *self.l1_rollup.address()) + .await?; + let batch_header = next_input.parent_batch_header; + validate_canonical_header( + batch_header.as_ref(), + batch_num, + prev.batch_hash, + ¤t_input, + )?; + let mut hasher = Keccak256::new(); + hasher.update(batch_header.as_ref()); + let header_hash = hasher.finalize(); + if header_hash != current.batch_hash { + return Err(anyhow!( + "canonical batch header hash mismatch: event={:?}, calldata={:?}", + current.batch_hash, + header_hash + )); + } + self.assert_snapshot(snapshot, snapshot_hash).await?; - log::info!("Found the specified batch (prev/curr/next): {:?}", batch_index_hash); - Ok(Some((batch_info, batch_input.0))) + log::info!( + "Found canonical specified batch: batch_index={}, commit_identity={:?}", + batch_num, + current.identity + ); + Ok(Some((batch_info, batch_header))) } /** @@ -390,18 +291,30 @@ where // Inspect blocks range and total txn count in a batch. async fn batch_blocks_inspect( &self, - prev_batch_hash: TxHash, - current_batch_hash: TxHash, - ) -> Option<((u64, u64), u64)> { - let prev_batch_input = batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; + prev: &CanonicalCommit, + current: &CanonicalCommit, + ) -> Result<(((u64, u64), u64), BatchDataInput)> { + let rollup_address = *self.l1_rollup.address(); + let prev_batch_input = + canonical_batch_input_inspect(&self.l1_provider, prev, rollup_address).await?; let current_batch_input = - batch_input_inspect(&self.l1_provider, current_batch_hash).await?; - let start_block = prev_batch_input.1 + 1; - let end_block = current_batch_input.1; + canonical_batch_input_inspect(&self.l1_provider, current, rollup_address).await?; + let start_block = prev_batch_input + .last_block_number + .checked_add(1) + .ok_or_else(|| anyhow!("previous batch last block overflows"))?; + let end_block = current_batch_input.last_block_number; if start_block == 0 { - log::error!("batch_blocks_inspect: start_block = 0, tx_hash = {:#?}", prev_batch_hash); - return None; + return Err(anyhow!( + "batch_blocks_inspect: start_block = 0, tx_hash = {:?}", + prev.transaction_hash + )); + } + if start_block > end_block { + return Err(anyhow!( + "batch_blocks_inspect: invalid block range {start_block}..={end_block}" + )); } let mut total_tx_count: u64 = 0; @@ -416,7 +329,9 @@ where } let results = join_all(tasks).await; for res in results { - total_tx_count += res.unwrap_or_default().unwrap_or_default(); + total_tx_count += res + .context("query L2 block transaction count")? + .ok_or_else(|| anyhow!("L2 block transaction count is unavailable"))?; } } @@ -429,7 +344,7 @@ where METRICS.shadow_txn_len.set(total_tx_count as i64); - Some(((start_block, end_block), total_tx_count)) + Ok((((start_block, end_block), total_tx_count), current_batch_input)) } // Check whether a batch has been proved successfully. @@ -509,17 +424,129 @@ pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Opt log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let param = if let Ok(_param) = Rollup::commitBatchCall::abi_decode(data) { - _param - } else { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); - return None; + let param = match decode_batch_data_input(data) { + Ok(param) => param, + Err(err) => { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); + log::debug!("batch inspect decode error: {err:#}"); + return None; + } }; - let parent_batch_header: Bytes = param.batchDataInput.parentBatchHeader; - let last_block_number: u64 = param.batchDataInput.lastBlockNumber; + let parent_batch_header = param.parent_batch_header; + let last_block_number = param.last_block_number; Some((parent_batch_header, last_block_number)) } + +async fn canonical_batch_input_inspect( + l1_provider: &DynProvider, + commit: &CanonicalCommit, + rollup_address: Address, +) -> Result { + let tx = l1_provider + .get_transaction_by_hash(commit.transaction_hash) + .await? + .ok_or_else(|| anyhow!("canonical commit transaction is unavailable"))?; + if tx.to() != Some(rollup_address) || + tx.block_number != Some(commit.identity.block_number) || + tx.transaction_index != Some(commit.identity.transaction_index) || + tx.block_hash != Some(commit.block_hash) + { + return Err(anyhow!( + "canonical commit transaction identity mismatch: expected={:?}, tx_block={:?}, tx_index={:?}, tx_block_hash={:?}", + commit.identity, + tx.block_number, + tx.transaction_index, + tx.block_hash + )); + } + decode_batch_data_input(tx.input()) +} + +fn validate_canonical_header( + header: &[u8], + expected_batch_index: u64, + expected_parent_hash: B256, + input: &BatchDataInput, +) -> Result<()> { + let minimum_len = if input.version == 0 { 249 } else { 257 }; + if header.len() < minimum_len { + return Err(anyhow!( + "canonical batch header is too short: version={}, len={}", + input.version, + header.len() + )); + } + if header[0] != input.version { + return Err(anyhow!("canonical batch header version mismatch")); + } + if u64::from_be_bytes(header[1..9].try_into().unwrap()) != expected_batch_index { + return Err(anyhow!("canonical batch header index mismatch")); + } + if header[89..121] != input.prev_state_root || + header[121..153] != input.post_state_root || + header[153..185] != input.withdrawal_root + { + return Err(anyhow!("canonical batch header root mismatch")); + } + if header[217..249] != expected_parent_hash[..] { + return Err(anyhow!("canonical batch header parent hash mismatch")); + } + if input.version > 0 && + u64::from_be_bytes(header[249..257].try_into().unwrap()) != input.last_block_number + { + return Err(anyhow!("canonical batch header last block mismatch")); + } + Ok(()) +} + +#[cfg(test)] +mod canonical_header_tests { + use super::*; + use crate::rollup_compat::SubmissionKind; + + fn fixture() -> (Vec, BatchDataInput, B256) { + let parent_hash = B256::repeat_byte(0x44); + let input = BatchDataInput { + version: 2, + parent_batch_header: Bytes::new(), + last_block_number: 123, + num_l1_messages: 0, + prev_state_root: [0x11; 32], + post_state_root: [0x22; 32], + withdrawal_root: [0x33; 32], + kind: SubmissionKind::CommitBatch, + pre_submitter: false, + }; + let mut header = vec![0u8; 257]; + header[0] = input.version; + header[1..9].copy_from_slice(&7u64.to_be_bytes()); + header[89..121].copy_from_slice(&input.prev_state_root); + header[121..153].copy_from_slice(&input.post_state_root); + header[153..185].copy_from_slice(&input.withdrawal_root); + header[217..249].copy_from_slice(parent_hash.as_slice()); + header[249..257].copy_from_slice(&input.last_block_number.to_be_bytes()); + (header, input, parent_hash) + } + + #[test] + fn canonical_header_matches_calldata_roots_parent_and_range() { + let (header, input, parent_hash) = fixture(); + validate_canonical_header(&header, 7, parent_hash, &input).unwrap(); + } + + #[test] + fn canonical_header_mismatch_fails_closed() { + let (mut header, input, parent_hash) = fixture(); + header[121] ^= 1; + assert!(validate_canonical_header(&header, 7, parent_hash, &input).is_err()); + + let (mut header, input, parent_hash) = fixture(); + header[256] ^= 1; + assert!(validate_canonical_header(&header, 7, parent_hash, &input).is_err()); + } +} #[tokio::test] +#[ignore = "requires configured L1/L2 RPCs and a funded signer"] async fn test_sync_batch() { use alloy_network::EthereumWallet; use alloy_primitives::Address; @@ -546,6 +573,10 @@ async fn test_sync_batch() { let rollup = var("SHADOW_PROVING_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let shadow_rollup = var("SHADOW_PROVING_L1_SHADOW_ROLLUP").expect("Cannot detect L1_SHADOW_ROLLUP env var"); + let rollup_deployed_block = var("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK") + .unwrap_or_else(|_| "1".to_string()) + .parse() + .unwrap(); let l1_signer = ProviderBuilder::new().wallet(wallet).connect_http(l1_rpc.parse().unwrap()); @@ -555,12 +586,14 @@ async fn test_sync_batch() { l1_provider, l2_provider, l1_signer, + rollup_deployed_block, ); let batch = bs.get_committed_batch().await.unwrap().unwrap(); bs.sync_batch(batch.0, batch.1).await.unwrap(); } #[tokio::test] +#[ignore = "requires an authenticated historical L1 RPC fixture"] async fn test_inspect_batch_header() { use alloy_primitives::B256; use alloy_provider::ProviderBuilder; diff --git a/prover/bin/shadow-prove/src/util.rs b/prover/bin/shadow-prove/src/util.rs index 4858f7e3b..9aa8aaf64 100644 --- a/prover/bin/shadow-prove/src/util.rs +++ b/prover/bin/shadow-prove/src/util.rs @@ -50,6 +50,7 @@ pub fn read_parse_env(var_name: &'static str) -> T { } #[tokio::test] +#[ignore = "requires SHADOW_PROVING_PROVER_RPC and an external prover service"] async fn test_call_prover() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); dotenv::dotenv().ok(); From b9bf687e0573c2aadbcc5e2330e6a46fd75b4fee Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:52:59 +0800 Subject: [PATCH 09/38] fix(challenge): preserve pre-cutover authority reads --- prover/bin/challenge/src/abi/mod.rs | 5 + .../abi/pre_submitter/LegacyL1Staking.json | 34 ++++++ .../bin/challenge/src/bin/auto_challenge.rs | 8 +- prover/bin/challenge/src/handler.rs | 35 +++--- prover/bin/challenge/src/rollup_compat.rs | 111 +++++++++++++++++- 5 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index b62b8e5cc..f6a612f04 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -13,6 +13,11 @@ pub mod pre_submitter_rollup_abi { abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); } +pub mod legacy_l1_staking_abi { + use ethers::prelude::abigen; + abigen!(LegacyL1Staking, "src/abi/pre_submitter/LegacyL1Staking.json"); +} + pub mod submitter_abi { use ethers::prelude::abigen; abigen!(Submitter, "src/abi/Submitter.json"); diff --git a/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json b/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json new file mode 100644 index 000000000..9d0abd2e7 --- /dev/null +++ b/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json @@ -0,0 +1,34 @@ +[ + { + "inputs": [], + "name": "challengeDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isActiveStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index e7f06fe62..2d41cda37 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -1,5 +1,5 @@ -use challenge_handler::abi::{rollup_abi::Rollup, submitter_abi::Submitter}; -use challenge_handler::rollup_compat::resolve_canonical_commit; +use challenge_handler::abi::rollup_abi::Rollup; +use challenge_handler::rollup_compat::{challenge_deposit_at, resolve_canonical_commit}; use challenge_handler::util::read_parse_env; use dotenv::dotenv; use env_logger::Env; @@ -112,9 +112,7 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, ro log::info!("latest blocknum = {:#?}", latest); let block_id = BlockId::Number(BlockNumber::Number(latest)); - let submitter_address = l1_rollup.submitter_contract().block(block_id).call().await?; - let submitter = Submitter::new(submitter_address, l1_rollup.client()); - let min_deposit = submitter.challenge_deposit().block(block_id).call().await?; + let min_deposit = challenge_deposit_at(l1_rollup, block_id).await?; let batch_index = l1_rollup.last_committed_batch_index().block(block_id).call().await?.as_u64(); if resolve_canonical_commit(l1_rollup, l1_provider, batch_index, rollup_deployed_block, latest) .await? diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index c949799ed..572d17a7a 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,7 +1,9 @@ -use crate::abi::{rollup_abi::Rollup, submitter_abi::Submitter}; +use crate::abi::rollup_abi::Rollup; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; -use crate::rollup_compat::{decode_batch_data_input, resolve_canonical_commit, CanonicalCommit}; +use crate::rollup_compat::{ + authority_is_active, decode_batch_data_input, decode_batch_data_store_block_number, resolve_canonical_commit, CanonicalCommit, +}; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; use ethers::prelude::*; @@ -327,23 +329,15 @@ impl ChallengeHandler { } }; let snapshot = BlockId::Number(BlockNumber::Number(number)); - let submitter_address = match l1_rollup.submitter_contract().block(snapshot).call().await { - Ok(address) => address, - Err(err) => { - log::error!("query Rollup.submitterContract failed: {err:#}"); - return false; - } - }; - let submitter = Submitter::new(submitter_address, l1_rollup.client()); - let active = match submitter.is_active(signer).block(snapshot).call().await { + let active = match authority_is_active(l1_rollup, signer, snapshot).await { Ok(active) => active, Err(err) => { - log::error!("Submitter.isActive preflight failed: {err:#}"); + log::error!("Rollup authority active preflight failed: {err:#}"); return false; } }; if !snapshot_unchanged(&self.l1_provider, number, hash).await { - log::error!("finalized snapshot changed during Submitter.isActive preflight"); + log::error!("finalized snapshot changed during authority active preflight"); return false; } if !active { @@ -493,10 +487,19 @@ async fn batch_inspect( snapshot: U64, ) -> Option { let block_id = BlockId::Number(BlockNumber::Number(snapshot)); - let prev_batch_last_bn: U256 = match l1_rollup.batch_data_store(U256::from(batch_index - 1)).block(block_id).call().await { - Ok(s) => s.2, + let parent_index = batch_index.checked_sub(1)?; + let calldata = l1_rollup.batch_data_store(U256::from(parent_index)).calldata()?; + let request: TypedTransaction = TransactionRequest::new().to(l1_rollup.address()).data(calldata).into(); + let prev_batch_last_bn: U256 = match l1_provider.call(&request, Some(block_id)).await { + Ok(data) => match decode_batch_data_store_block_number(data.as_ref()) { + Ok(block_number) => block_number, + Err(error) => { + log::error!("decode compatible batchDataStore output failed: {error:#}"); + return None; + } + }, Err(e) => { - log::error!("l1_rollup.batch_data_store err: {:#?}", e); + log::error!("l1_rollup compatible batchDataStore call failed: {:#?}", e); return None; } }; diff --git a/prover/bin/challenge/src/rollup_compat.rs b/prover/bin/challenge/src/rollup_compat.rs index a55432706..fc0875cbe 100644 --- a/prover/bin/challenge/src/rollup_compat.rs +++ b/prover/bin/challenge/src/rollup_compat.rs @@ -1,19 +1,109 @@ use ethers::{ abi::AbiDecode, providers::Middleware, - types::{BlockId, BlockNumber, Bytes, Filter, Log, TxHash, H256, U256, U64}, - utils::keccak256, + types::{transaction::eip2718::TypedTransaction, Address, BlockId, BlockNumber, Bytes, Filter, Log, TransactionRequest, TxHash, H256, U256, U64}, + utils::{id, keccak256}, }; use eyre::{eyre, Result}; use crate::abi::{ + legacy_l1_staking_abi::LegacyL1Staking, pre_submitter_rollup_abi::{ CommitBatchCall as PreSubmitterCommitBatchCall, CommitBatchWithProofCall as PreSubmitterCommitBatchWithProofCall, CommitStateCall as PreSubmitterCommitStateCall, }, rollup_abi::{CommitBatchCall, CommitBatchWithProofCall, CommitStateCall, Rollup}, + submitter_abi::Submitter, }; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum AuthorityKind { + LegacyL1Staking, + Submitter, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RollupAuthority { + pub address: Address, + pub kind: AuthorityKind, +} + +fn decode_address_word(data: &[u8]) -> Result
{ + if data.len() != 32 || data[..12].iter().any(|byte| *byte != 0) { + return Err(eyre!("authority getter returned malformed address data")); + } + let address = Address::from_slice(&data[12..]); + if address.is_zero() { + return Err(eyre!("authority getter returned zero address")); + } + Ok(address) +} + +pub async fn resolve_rollup_authority(rollup: &Rollup, snapshot: BlockId) -> Result { + match rollup.submitter_contract().block(snapshot).call().await { + Ok(address) if !address.is_zero() => Ok(RollupAuthority { + address, + kind: AuthorityKind::Submitter, + }), + Ok(_) => Err(eyre!("Rollup.submitterContract returned zero address")), + Err(current_error) => { + // Before initialize4 the proxy still runs the frozen Rollup ABI and + // rejects submitterContract(). Read the old slot through its + // historical getter at the exact same numbered snapshot. + let request: TypedTransaction = TransactionRequest::new() + .to(rollup.address()) + .data(Bytes::from(id("l1StakingContract()")[..4].to_vec())) + .into(); + let output = rollup.client().call(&request, Some(snapshot)).await.map_err(|legacy_error| { + eyre!("neither current nor pre-submit authority getter succeeded: current={current_error}; legacy={legacy_error}") + })?; + Ok(RollupAuthority { + address: decode_address_word(output.as_ref())?, + kind: AuthorityKind::LegacyL1Staking, + }) + } + } +} + +pub async fn authority_is_active(rollup: &Rollup, signer: Address, snapshot: BlockId) -> Result { + let authority = resolve_rollup_authority(rollup, snapshot).await?; + match authority.kind { + AuthorityKind::Submitter => Ok(Submitter::new(authority.address, rollup.client()) + .is_active(signer) + .block(snapshot) + .call() + .await?), + AuthorityKind::LegacyL1Staking => Ok(LegacyL1Staking::new(authority.address, rollup.client()) + .is_active_staker(signer) + .block(snapshot) + .call() + .await?), + } +} + +pub async fn challenge_deposit_at(rollup: &Rollup, snapshot: BlockId) -> Result { + let authority = resolve_rollup_authority(rollup, snapshot).await?; + match authority.kind { + AuthorityKind::Submitter => Ok(Submitter::new(authority.address, rollup.client()) + .challenge_deposit() + .block(snapshot) + .call() + .await?), + AuthorityKind::LegacyL1Staking => Ok(LegacyL1Staking::new(authority.address, rollup.client()) + .challenge_deposit() + .block(snapshot) + .call() + .await?), + } +} + +pub fn decode_batch_data_store_block_number(data: &[u8]) -> Result { + if data.len() != 128 { + return Err(eyre!("batchDataStore returned {}, expected exactly 128 bytes", data.len())); + } + Ok(U256::from_big_endian(&data[64..96])) +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum SubmissionKind { CommitBatch, @@ -250,4 +340,21 @@ mod tests { let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); } + + #[test] + fn compatibility_words_reject_malformed_authority_and_ignore_legacy_bitmap_type() { + let address = Address::from_low_u64_be(7); + let mut address_word = [0u8; 32]; + address_word[12..].copy_from_slice(address.as_bytes()); + assert_eq!(decode_address_word(&address_word).unwrap(), address); + assert!(decode_address_word(&address_word[..31]).is_err()); + address_word[0] = 1; + assert!(decode_address_word(&address_word).is_err()); + + let mut old_tuple = [0u8; 128]; + U256::from(123).to_big_endian(&mut old_tuple[64..96]); + old_tuple[96..128].fill(0xff); // legacy uint256 bitmap, not an ABI address + assert_eq!(decode_batch_data_store_block_number(&old_tuple).unwrap(), U256::from(123)); + assert!(decode_batch_data_store_block_number(&old_tuple[..127]).is_err()); + } } From a7dea9846cae0f0e237d780ac1a12e63f4029d06 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 20:54:51 +0800 Subject: [PATCH 10/38] feat(ops): configure static validators and submitter runtime --- node/ops-morph/docker-compose.yml | 4 +- node/ops-morph/testnet/docker-compose.yml | 8 +- node/ops-morph/testnet/launch.sh | 9 +- ops/devnet-morph/devnet/__init__.py | 100 +++++++++++++++---- ops/devnet-morph/tests/test_devnet_config.py | 36 +++++++ ops/docker/.env | 8 +- ops/docker/docker-compose-cluster.yml | 3 + ops/docker/docker-compose-devnet.yml | 11 +- 8 files changed, 146 insertions(+), 33 deletions(-) diff --git a/node/ops-morph/docker-compose.yml b/node/ops-morph/docker-compose.yml index 4f9106aad..0ca681209 100644 --- a/node/ops-morph/docker-compose.yml +++ b/node/ops-morph/docker-compose.yml @@ -49,7 +49,7 @@ services: - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --dev-sequencer + --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} --home $NODE_DATA_DIR tx-submitter: @@ -70,4 +70,4 @@ services: - TX_SUBMITTER_BATCH_BLOCK_NUM=1 - TX_SUBMITTER_BATCH_NUM=1 - TX_SUBMITTER_FIRST_TIME=true - - TX_SUBMITTER_CHAIN_ID=900 \ No newline at end of file + - TX_SUBMITTER_CHAIN_ID=900 diff --git a/node/ops-morph/testnet/docker-compose.yml b/node/ops-morph/testnet/docker-compose.yml index d0322fb09..b58418c1e 100644 --- a/node/ops-morph/testnet/docker-compose.yml +++ b/node/ops-morph/testnet/docker-compose.yml @@ -129,7 +129,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --dev-sequencer + --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} --home $NODE_DATA_DIR node-1: @@ -153,7 +153,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --dev-sequencer + --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} --home $NODE_DATA_DIR node-2: @@ -177,7 +177,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --dev-sequencer + --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} --home $NODE_DATA_DIR node-3: @@ -201,5 +201,5 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --dev-sequencer + --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} --home $NODE_DATA_DIR diff --git a/node/ops-morph/testnet/launch.sh b/node/ops-morph/testnet/launch.sh index 3394279ec..dff9c4f85 100644 --- a/node/ops-morph/testnet/launch.sh +++ b/node/ops-morph/testnet/launch.sh @@ -3,8 +3,9 @@ export MORPH_NODE_L2_ENGINE_AUTH=ops-morph/jwt-secret.txt export MORPH_NODE_L1_ETH_RPC=https://eth-goerli.g.alchemy.com/v2/hmGN_z77oy7LlFgPivFuKF893Iog5AOV export MORPH_NODE_SYNC_DEPOSIT_CONTRACT_ADDRESS=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 +: "${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?set the comma-separated network Tendermint ed25519 public keys}" -nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node0 --l2.eth=http://127.0.0.1:8545 --l2.engine=http://127.0.0.1:8551 > ./mytestnet/node0.log 2>&1 & -nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node1 --l2.eth=http://127.0.0.1:8645 --l2.engine=http://127.0.0.1:8651 > ./mytestnet/node1.log 2>&1 & -nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node2 --l2.eth=http://127.0.0.1:8745 --l2.engine=http://127.0.0.1:8751 > ./mytestnet/node2.log 2>&1 & -nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node3 --l2.eth=http://127.0.0.1:8845 --l2.engine=http://127.0.0.1:8851 > ./mytestnet/node3.log 2>&1 & \ No newline at end of file +nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node0 --l2.eth=http://127.0.0.1:8545 --l2.engine=http://127.0.0.1:8551 > ./mytestnet/node0.log 2>&1 & +nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node1 --l2.eth=http://127.0.0.1:8645 --l2.engine=http://127.0.0.1:8651 > ./mytestnet/node1.log 2>&1 & +nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node2 --l2.eth=http://127.0.0.1:8745 --l2.engine=http://127.0.0.1:8751 > ./mytestnet/node2.log 2>&1 & +nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node3 --l2.eth=http://127.0.0.1:8845 --l2.engine=http://127.0.0.1:8851 > ./mytestnet/node3.log 2>&1 & diff --git a/ops/devnet-morph/devnet/__init__.py b/ops/devnet-morph/devnet/__init__.py index 020efb254..a226e20c5 100644 --- a/ops/devnet-morph/devnet/__init__.py +++ b/ops/devnet-morph/devnet/__init__.py @@ -1,4 +1,6 @@ import argparse +import base64 +import binascii import logging import os import subprocess @@ -44,6 +46,24 @@ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', ), help='Private key for the L1 contract deployer/owner') +parser.add_argument('--batch-submitter-private-key', + default=os.environ.get( + 'BATCH_SUBMITTER_PRIVATE_KEY', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + ), + help='Independent private key used by the devnet batch submitter') +parser.add_argument('--batch-submitter-address', + default=os.environ.get( + 'BATCH_SUBMITTER_ADDRESS', + '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', + ), + help='Address expected to match --batch-submitter-private-key') +parser.add_argument('--legacy-genesis-l1-staking-proxy', + default=os.environ.get( + 'LEGACY_GENESIS_L1_STAKING_PROXY', + '0x000000000000000000000000000000000000dEaD', + ), + help='Immutable-only legacy OTHER_STAKING fixture; never used as Submitter') parser.add_argument('--cluster', action="store_true", default=os.environ.get('DEVNET_CLUSTER', '').lower() in ('1', 'true', 'yes'), help='Start an HA sequencer cluster instead of making node-0 the sequencer') @@ -196,6 +216,10 @@ def devnet_deploy(paths, args): deploy_config = read_json(devnet_cfg_orig) deploy_config['l1GenesisBlockTimestamp'] = "0x{:x}".format(int(time.time())) deploy_config['l1StartingBlockTag'] = 'earliest' + # The current L2 genesis format still has the historical OTHER_STAKING + # immutable. Keep that fixture explicit and separate from the live + # Submitter address; it must never be renamed or repointed to Submitter. + deploy_config['l1StakingProxy'] = args.legacy_genesis_l1_staking_proxy temp_deploy_config = pjoin(paths.devnet_dir, 'deploy-config.json') write_json(temp_deploy_config, deploy_config) @@ -252,29 +276,46 @@ def devnet_deploy(paths, args): log.info('Parser L1 contracts...') addresses = {} + deployment_blocks = {} deployment = read_json(paths.deployment_dir) for d in deployment: addresses[d['name']] = d['address'] + deployment_blocks[d['name']] = int(d['number']) log.info('Passing L1 contracts address:', addresses) - log.info('Do Staking Sequencer...') - deploy_config['l2StakingAddresses'] - deploy_config['l2StakingPks'] - deploy_config['l2StakingTmKeys'] - deploy_config['l2StakingBlsKeys'] - for i in range(4): - run_command(['cast', 'send', addresses['Proxy__L1Staking'], - 'register(bytes32,bytes memory)', - deploy_config['l2StakingTmKeys'][i], - deploy_config['l2StakingBlsKeys'][i], - '--rpc-url', 'http://127.0.0.1:9545', - '--value', '1ether', - '--private-key', deploy_config['l2StakingPks'][i] - ]) + rollup_deployed_block = deployment_blocks.get('Proxy__Rollup', 0) + if rollup_deployed_block <= 0: + raise RuntimeError('Proxy__Rollup deployment block missing from deployment output') + + log.info('Registering and funding the independent batch submitter...') + submitter_proxy = addresses['Proxy__Submitter'] + if submitter_proxy.lower() == args.legacy_genesis_l1_staking_proxy.lower(): + raise RuntimeError( + 'live Proxy__Submitter must differ from immutable legacy L1 staking fixture' + ) + submitter_address = run_command_capture_output([ + 'cast', 'wallet', 'address', '--private-key', args.batch_submitter_private_key, + ], cwd=paths.contracts_dir).stdout.strip() + if submitter_address.lower() != args.batch_submitter_address.lower(): + raise RuntimeError( + f'batch submitter key resolves to {submitter_address}, expected {args.batch_submitter_address}' + ) + run_command([ + 'cast', 'send', submitter_proxy, 'addSubmitter(address)', submitter_address, + '--rpc-url', 'http://127.0.0.1:9545', + '--private-key', args.deployer_private_key, + ], cwd=paths.contracts_dir) + run_command([ + 'cast', 'send', submitter_proxy, 'stake()', + '--rpc-url', 'http://127.0.0.1:9545', + '--value', '1ether', + '--private-key', args.batch_submitter_private_key, + ], cwd=paths.contracts_dir) configure_l1_sequencer(paths, args, addresses, deploy_config) sequencer_upgrade_time = int((time.time() + args.sequencer_upgrade_offset_seconds) * 1000) active_sequencer_private_key = '' if args.cluster else args.sequencer_private_key + static_validator_tm_keys = read_static_validator_tm_keys(paths.ops_dir) log.info( f'Single sequencer mode enabled: sequencer={args.sequencer_address}, cluster={args.cluster}, ' f'upgrade_time_ms={sequencer_upgrade_time}, ' @@ -293,17 +334,25 @@ def devnet_deploy(paths, args): if line and not line.startswith('#'): key, value = line.split('=') env_data[key.strip()] = value.strip() + # Never carry the retired runtime authority forward from an older + # tracked/local .env. The only allowed legacy staking address is the + # explicit immutable genesis fixture above. + env_data.pop('Proxy__L1Staking', None) + env_data.pop('MORPH_L1STAKING', None) env_data['L1_CROSS_DOMAIN_MESSENGER'] = addresses['Proxy__L1CrossDomainMessenger'] env_data['MORPH_PORTAL'] = addresses['Proxy__L1MessageQueueWithGasPriceOracle'] env_data['MORPH_ROLLUP'] = addresses['Proxy__Rollup'] + env_data['MORPH_ROLLUP_DEPLOY_BLOCK'] = str(rollup_deployed_block) env_data['RUST_LOG'] = rust_log_level - env_data['Proxy__L1Staking'] = addresses['Proxy__L1Staking'] - env_data['MORPH_L1STAKING'] = addresses['Proxy__L1Staking'] + env_data['Proxy__Submitter'] = submitter_proxy + env_data['MORPH_SUBMITTER'] = submitter_proxy env_data['L1_SEQUENCER_CONTRACT'] = addresses.get('Proxy__L1Sequencer', '') env_data['SEQUENCER_PRIVATE_KEY'] = args.sequencer_private_key env_data['ACTIVE_SEQUENCER_PRIVATE_KEY'] = active_sequencer_private_key env_data['HA_SEQUENCER_ADDR'] = args.sequencer_address env_data['SEQUENCER_UPGRADE_TIME'] = str(sequencer_upgrade_time) + env_data['MORPH_NODE_STATIC_VALIDATOR_TM_KEYS'] = static_validator_tm_keys + env_data['BATCH_SUBMITTER_PRIVATE_KEY'] = args.batch_submitter_private_key envfile.seek(0) for key, value in env_data.items(): envfile.write(f'{key}={value}\n') @@ -318,7 +367,9 @@ def devnet_deploy(paths, args): env={ 'MORPH_PORTAL': addresses['Proxy__L1MessageQueueWithGasPriceOracle'], 'MORPH_ROLLUP': addresses['Proxy__Rollup'], - 'MORPH_L1STAKING': addresses['Proxy__L1Staking'], + 'MORPH_ROLLUP_DEPLOY_BLOCK': str(rollup_deployed_block), + 'MORPH_SUBMITTER': submitter_proxy, + 'BATCH_SUBMITTER_PRIVATE_KEY': args.batch_submitter_private_key, 'PWD': paths.ops_dir, 'NODE_DATA_DIR': '/data', 'GETH_DATA_DIR': '/db', @@ -329,11 +380,26 @@ def devnet_deploy(paths, args): 'SEQUENCER_PRIVATE_KEY': args.sequencer_private_key, 'ACTIVE_SEQUENCER_PRIVATE_KEY': active_sequencer_private_key, 'SEQUENCER_UPGRADE_TIME': str(sequencer_upgrade_time), + 'MORPH_NODE_STATIC_VALIDATOR_TM_KEYS': static_validator_tm_keys, }) wait_up(8545) wait_for_rpc_server('127.0.0.1:8545') +def read_static_validator_tm_keys(ops_dir): + """Load and validate the devnet's canonical Tendermint ed25519 public key.""" + key_path = pjoin(ops_dir, 'node0', 'priv_validator_key.json') + with open(key_path, 'r', encoding='utf-8') as key_file: + encoded = json.load(key_file)['pub_key']['value'] + try: + key = base64.b64decode(encoded, validate=True) + except (ValueError, binascii.Error) as error: + raise RuntimeError(f'invalid Tendermint validator public key in {key_path}') from error + if len(key) != 32: + raise RuntimeError(f'Tendermint validator public key in {key_path} must be 32 bytes') + return key.hex() + + def configure_l1_sequencer(paths, args, addresses, deploy_config): """Register the devnet's single sequencer in L1Sequencer before starting L2.""" l1_sequencer_addr = addresses.get('Proxy__L1Sequencer', '') diff --git a/ops/devnet-morph/tests/test_devnet_config.py b/ops/devnet-morph/tests/test_devnet_config.py index f64532279..fa616d047 100644 --- a/ops/devnet-morph/tests/test_devnet_config.py +++ b/ops/devnet-morph/tests/test_devnet_config.py @@ -92,6 +92,42 @@ def test_compose_file_args_can_enable_cluster_mode(self): ], ) + def test_centralized_runtime_uses_submitter_and_static_validator_inputs(self): + compose = (DOCKER_DIR / "docker-compose-devnet.yml").read_text() + env_file = (DOCKER_DIR / ".env").read_text() + devnet_source = (DEVNET_PACKAGE / "devnet" / "__init__.py").read_text() + + self.assertNotIn("Proxy__L1Staking=", env_file) + self.assertNotIn("MORPH_L1STAKING=", env_file) + self.assertIn("MORPH_SUBMITTER=", env_file) + self.assertIn("BATCH_SUBMITTER_PRIVATE_KEY=", env_file) + self.assertIn("MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=", env_file) + self.assertIn("MORPH_ROLLUP_DEPLOY_BLOCK=", env_file) + + env_values = dict( + line.split("=", 1) + for line in env_file.splitlines() + if line and not line.startswith("#") + ) + self.assertNotEqual( + env_values["LEGACY_GENESIS_L1_STAKING_PROXY"].lower(), + env_values["MORPH_SUBMITTER"].lower(), + ) + + self.assertIn("TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER:?required}", compose) + self.assertIn( + "GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK=${MORPH_ROLLUP_DEPLOY_BLOCK:?required}", + compose, + ) + self.assertNotIn("l2StakingPks", devnet_source) + self.assertIn("--batch-submitter-private-key", devnet_source) + self.assertIn("env_data.pop('Proxy__L1Staking', None)", devnet_source) + self.assertIn("env_data.pop('MORPH_L1STAKING', None)", devnet_source) + self.assertIn( + "live Proxy__Submitter must differ from immutable legacy L1 staking fixture", + devnet_source, + ) + if __name__ == "__main__": unittest.main() diff --git a/ops/docker/.env b/ops/docker/.env index 670440268..3d1c7c4c1 100644 --- a/ops/docker/.env +++ b/ops/docker/.env @@ -7,9 +7,13 @@ L1_BEACON_CHAIN_RPC=http://layer1-cl:4000 L1_CROSS_DOMAIN_MESSENGER=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 MORPH_PORTAL=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 MORPH_ROLLUP=0xa513e6e4b8f2a923d98304ec87f64353c4d5c853 +MORPH_ROLLUP_DEPLOY_BLOCK=1 +LEGACY_GENESIS_L1_STAKING_PROXY=0x000000000000000000000000000000000000dEaD BUILD_GETH=l2-geth RUST_LOG=info -Proxy__L1Staking=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 BATCH_UPGRADE_TIME=0 -MORPH_L1STAKING=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 L1_SEQUENCER_CONTRACT=0x0165878a594ca255338adfa4d48449f69242eb8f +MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=5280d0eee2a64d3ad29480d15ffd1b048ce5908f180b5ccd65cc3dcf00941abb +BATCH_SUBMITTER_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d +Proxy__Submitter=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 +MORPH_SUBMITTER=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 diff --git a/ops/docker/docker-compose-cluster.yml b/ops/docker/docker-compose-cluster.yml index f5c75e6fb..900f10ee7 100644 --- a/ops/docker/docker-compose-cluster.yml +++ b/ops/docker/docker-compose-cluster.yml @@ -103,6 +103,7 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} + - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_BOOTSTRAP=true - MORPH_NODE_HA_SERVER_ID=ha-node-0 @@ -143,6 +144,7 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} + - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_JOIN=ha-node-0:9401 - MORPH_NODE_HA_SERVER_ID=ha-node-1 @@ -183,6 +185,7 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} + - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_JOIN=ha-node-0:9401 - MORPH_NODE_HA_SERVER_ID=ha-node-2 diff --git a/ops/docker/docker-compose-devnet.yml b/ops/docker/docker-compose-devnet.yml index 451cd5e16..6809d24a8 100644 --- a/ops/docker/docker-compose-devnet.yml +++ b/ops/docker/docker-compose-devnet.yml @@ -185,6 +185,7 @@ services: - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - MORPH_NODE_SEQUENCER_PRIVATE_KEY=${ACTIVE_SEQUENCER_PRIVATE_KEY} - MORPH_NODE_SEQUENCER_UPGRADE_TIME=${SEQUENCER_UPGRADE_TIME:-0} + - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} volumes: - ".devnet/node0:${NODE_DATA_DIR}" - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" @@ -221,6 +222,7 @@ services: - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - MORPH_NODE_SEQUENCER_UPGRADE_TIME=${SEQUENCER_UPGRADE_TIME:-0} - MORPH_NODE_DERIVATION_VERIFY_MODE=layer1 + - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} volumes: - ".devnet/node1:${NODE_DATA_DIR}" - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" @@ -247,16 +249,16 @@ services: environment: - TX_SUBMITTER_BUILD_ENV=dev - TX_SUBMITTER_L1_ETH_RPC=${L1_ETH_RPC} - - TX_SUBMITTER_L1_PRIVATE_KEY=0xd99870855d97327d20c666abc78588f1449b1fac76ed0c86c1afb9ce2db85f32 + - TX_SUBMITTER_L1_PRIVATE_KEY=${BATCH_SUBMITTER_PRIVATE_KEY:?required} - TX_SUBMITTER_L2_ETH_RPCS=http://morph-el-0:8545,http://morph-el-1:8545 - TX_SUBMITTER_TX_TIMEOUT=60s - TX_SUBMITTER_ROLLUP_ADDRESS=${MORPH_ROLLUP:-0x6900000000000000000000000000000000000010} + - TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER:?required} - TX_SUBMITTER_FINALIZE=true - - TX_SUBMITTER_PRIORITY_ROLLUP=true - TX_SUBMITTER_SEAL_BATCH=true + - TX_SUBMITTER_BATCH_BLOCK_INTERVAL=200 + - TX_SUBMITTER_BATCH_TIMEOUT=600 - TX_SUBMITTER_TX_FEE_LIMIT=500000000000000000 - - TX_SUBMITTER_L1_STAKING_ADDRESS=${MORPH_L1STAKING:-0x5fc8d32690cc91d4c39d9d3abcbd16989f875707} - - TX_SUBMITTER_L1_STAKING_DEPLOYED_BLOCKNUM=0 - TX_SUBMITTER_BATCH_V2_UPGRADE_TIME=1777533291 gas-price-oracle: @@ -276,6 +278,7 @@ services: environment: - GAS_ORACLE_L1_RPC=${L1_ETH_RPC} - GAS_ORACLE_L1_BEACON_RPC=${L1_BEACON_CHAIN_RPC} + - GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK=${MORPH_ROLLUP_DEPLOY_BLOCK:?required} - GAS_ORACLE_L2_RPC=http://morph-el-0:8545 - GAS_THRESHOLD=5 - INTERVAL=28000 From ab92ddd5baa3dc510d7dfbc15773de39e665b08d Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:14:28 +0800 Subject: [PATCH 11/38] feat(gas-oracle): sample canonical blob sources --- gas-oracle/.env.dev | 5 +- gas-oracle/Makefile | 8 +- gas-oracle/app/Cargo.lock | 74 +- gas-oracle/app/Cargo.toml | 1 + gas-oracle/app/rust-toolchain | 2 +- gas-oracle/app/rustfmt.toml | 8 - gas-oracle/app/src/abi/Rollup.json | 288 +++++- gas-oracle/app/src/abi/mod.rs | 5 + gas-oracle/app/src/da_scalar/blob.rs | 8 +- gas-oracle/app/src/da_scalar/blob_client.rs | 8 +- gas-oracle/app/src/da_scalar/calculate.rs | 239 +++-- gas-oracle/app/src/da_scalar/error.rs | 1 - gas-oracle/app/src/da_scalar/l1_scalar.rs | 975 +++++++++++++++++--- gas-oracle/app/src/da_scalar/mod.rs | 2 +- gas-oracle/app/src/gas_price_oracle.rs | 12 +- gas-oracle/app/src/l1_base_fee.rs | 9 +- gas-oracle/app/src/lib.rs | 3 +- gas-oracle/app/src/metrics.rs | 8 +- gas-oracle/app/src/rollup_compat.rs | 299 ++++++ gas-oracle/app/src/signer.rs | 5 +- 20 files changed, 1696 insertions(+), 264 deletions(-) create mode 100644 gas-oracle/app/src/rollup_compat.rs diff --git a/gas-oracle/.env.dev b/gas-oracle/.env.dev index 3091dcb34..f59892b9c 100644 --- a/gas-oracle/.env.dev +++ b/gas-oracle/.env.dev @@ -13,6 +13,9 @@ TXN_PER_BLOCK = 1 TXN_PER_BATCH = 50 L1_ROLLUP = "0xC5386CBDa4864aE1F86Ed5840D370855F64Bcd3c" +# Sepolia Proxy creation tx 0xe0565450edc796d2ccf37f3c70c119a2db22d44021930bab3375852e36deec90. +# Production deployments must inject the block recorded in their deployment manifest. +GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK = 4239849 L2_GAS_PRICE_ORACLE = "0x5FbDB2315678afecb367f032d93F642f64180aa3" L2_GAS_ORACLE_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" @@ -27,4 +30,4 @@ GAS_ORACLE_EXTERNAL_SIGN_URL = "http://localhost:8080/v1/sign/tx_sign" GAS_ORACLE_L1_BASE_FEE_BUFFER = 0 GAS_ORACLE_L1_BLOB_BASE_FEE_BUFFER = 0 GAS_ORACLE_COMMIT_SCALAR_BUFFER = 0 -GAS_ORACLE_BLOB_SCALAR_BUFFER = 0 \ No newline at end of file +GAS_ORACLE_BLOB_SCALAR_BUFFER = 0 diff --git a/gas-oracle/Makefile b/gas-oracle/Makefile index c6ee078a8..05001fb6f 100644 --- a/gas-oracle/Makefile +++ b/gas-oracle/Makefile @@ -8,15 +8,15 @@ run:build # Run the formatter but don't change any files. fmt: - cd app && cargo +nightly fmt --all -- --check + cd app && cargo fmt --all -- --check # Run the formatter and update files with style changes lint: - cd app && cargo +nightly fmt --all + cd app && cargo fmt --all # Run clippy clippy: - cd app && cargo +nightly clippy --all-targets -- -D warnings + cd app && cargo clippy --all-targets -- -D warnings # Run all tests test: @@ -37,4 +37,4 @@ help: @echo "test: Run all tests" @echo "clean: Clean the builds" @echo "help: Show this help message" - @echo "" \ No newline at end of file + @echo "" diff --git a/gas-oracle/app/Cargo.lock b/gas-oracle/app/Cargo.lock index 2f6cccb68..c0f49cdb3 100644 --- a/gas-oracle/app/Cargo.lock +++ b/gas-oracle/app/Cargo.lock @@ -137,6 +137,7 @@ name = "app" version = "0.1.0" dependencies = [ "axum", + "c-kzg", "dotenv", "env_logger", "ethers", @@ -369,6 +370,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "brotli" version = "6.0.0" @@ -448,6 +461,21 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "c-kzg" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + [[package]] name = "camino" version = "1.1.7" @@ -482,13 +510,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ + "find-msvc-tools", "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1265,6 +1294,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -2260,9 +2295,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "open-fastrlp" @@ -3344,6 +3379,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3613,6 +3654,15 @@ dependencies = [ "syn 2.0.66", ] +[[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.36" @@ -4442,6 +4492,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] [[package]] name = "zip" diff --git a/gas-oracle/app/Cargo.toml b/gas-oracle/app/Cargo.toml index 7fbb3b4e1..29be3eefc 100644 --- a/gas-oracle/app/Cargo.toml +++ b/gas-oracle/app/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +c-kzg = "=2.1.5" ethers = { version = "2.0", features = ["optimism"] } tokio = { version = "1", features = ["full"] } dotenv = "0.15.0" diff --git a/gas-oracle/app/rust-toolchain b/gas-oracle/app/rust-toolchain index f1d81c421..6979a6c06 100644 --- a/gas-oracle/app/rust-toolchain +++ b/gas-oracle/app/rust-toolchain @@ -1 +1 @@ -nightly-2023-12-03 \ No newline at end of file +1.91.0 diff --git a/gas-oracle/app/rustfmt.toml b/gas-oracle/app/rustfmt.toml index 68c3c9303..057dc57df 100644 --- a/gas-oracle/app/rustfmt.toml +++ b/gas-oracle/app/rustfmt.toml @@ -1,11 +1,3 @@ reorder_imports = true -imports_granularity = "Crate" use_small_heuristics = "Max" -comment_width = 100 -wrap_comments = true -binop_separator = "Back" -trailing_comma = "Vertical" -trailing_semicolon = false use_field_init_shorthand = true -format_code_in_doc_comments = true -doc_comment_code_block_width = 100 diff --git a/gas-oracle/app/src/abi/Rollup.json b/gas-oracle/app/src/abi/Rollup.json index 28f7a5c6d..e9da0e250 100644 --- a/gas-oracle/app/src/abi/Rollup.json +++ b/gas-oracle/app/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -942,6 +1100,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "pendingBatchCount", + "outputs": [ + { + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proofRewardPercent", @@ -968,6 +1145,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1245,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1271,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1336,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/gas-oracle/app/src/abi/mod.rs b/gas-oracle/app/src/abi/mod.rs index fdcc9a2c2..2db3287a1 100644 --- a/gas-oracle/app/src/abi/mod.rs +++ b/gas-oracle/app/src/abi/mod.rs @@ -13,3 +13,8 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } + +pub mod pre_submitter_rollup_abi { + use ethers::prelude::abigen; + abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); +} diff --git a/gas-oracle/app/src/da_scalar/blob.rs b/gas-oracle/app/src/da_scalar/blob.rs index dea157f3c..4320cbbef 100644 --- a/gas-oracle/app/src/da_scalar/blob.rs +++ b/gas-oracle/app/src/da_scalar/blob.rs @@ -77,7 +77,7 @@ impl Blob { let max_payload_size = num_blobs * (MAX_BLOB_TX_PAYLOAD_SIZE - 4096); if compressed_len as usize > max_payload_size { - return Err(BlobError::Error(anyhow!("oversized batch payload"))) + return Err(BlobError::Error(anyhow!("oversized batch payload"))); } let compressed_batch = decoded_blob[..compressed_len].to_vec(); @@ -103,7 +103,7 @@ impl Blob { if origin_batch.len() != orgin_content_size as usize { return Err(BlobError::Error(anyhow!( "decompress batch error: origin_batch_len is not equal to zstd_orgin_content_size" - ))) + ))); } let total_blob_payload = num_blobs as f32 * (MAX_BLOB_TX_PAYLOAD_SIZE - 4096) as f32; @@ -163,8 +163,8 @@ fn parse_block_header( // resolve Block_Size (21 bits) let block_size = - ((header[0] as u32 >> 3) | ((header[1] as u32) << 5) | ((header[2] as u32) << 13)) & - 0x1FFFFF; + ((header[0] as u32 >> 3) | ((header[1] as u32) << 5) | ((header[2] as u32) << 13)) + & 0x1FFFFF; Ok((last_block, block_type, block_size)) } diff --git a/gas-oracle/app/src/da_scalar/blob_client.rs b/gas-oracle/app/src/da_scalar/blob_client.rs index 8a2f2871b..266a08659 100644 --- a/gas-oracle/app/src/da_scalar/blob_client.rs +++ b/gas-oracle/app/src/da_scalar/blob_client.rs @@ -26,10 +26,10 @@ impl BeaconNode { indexes: Vec, ) -> Result { let client = reqwest::blocking::Client::new(); - let mut url = l1_beacon_rpc.to_owned() + - "/eth/v1/beacon/blob_sidecars/" + - slot.to_string().as_str() + - "?"; + let mut url = l1_beacon_rpc.to_owned() + + "/eth/v1/beacon/blob_sidecars/" + + slot.to_string().as_str() + + "?"; for index in indexes { url = url + "indices=" + index.to_string().as_str() + "&"; } diff --git a/gas-oracle/app/src/da_scalar/calculate.rs b/gas-oracle/app/src/da_scalar/calculate.rs index 7e7df970a..b67251129 100644 --- a/gas-oracle/app/src/da_scalar/calculate.rs +++ b/gas-oracle/app/src/da_scalar/calculate.rs @@ -1,18 +1,108 @@ +use std::collections::BTreeMap; + +use c_kzg::{ethereum_kzg_settings, Blob as KzgBlob, Bytes48}; use ethers::{ prelude::*, utils::{hex, rlp}, }; use eyre::anyhow; -use serde::{Deserialize, Serialize}; use serde_json::Value; use super::{ - blob::{decompress_batch, kzg_to_versioned_hash, Blob}, + blob::{decompress_batch, kzg_to_versioned_hash, Blob as MorphBlob}, error::ScalarError, typed_tx::TypedTransaction, MAX_BLOB_TX_PAYLOAD_SIZE, }; +fn sidecar_index(sidecar: &Value) -> Result { + let raw = sidecar.get("index").and_then(Value::as_str).ok_or_else(|| { + ScalarError::CalculateError(anyhow!("beacon blob sidecar index is missing or not a string")) + })?; + if raw.is_empty() || !raw.bytes().all(|byte| byte.is_ascii_digit()) { + return Err(ScalarError::CalculateError(anyhow!( + "beacon blob sidecar index is not an unsigned decimal integer" + ))); + } + raw.parse::().map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar index overflows u64: {e}" + ))) + }) +} + +fn decode_beacon_hex( + sidecar: &Value, + field: &'static str, + expected_len: usize, +) -> Result, ScalarError> { + let encoded = sidecar.get(field).and_then(Value::as_str).ok_or_else(|| { + ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar {field} is missing or not a string" + ))) + })?; + let payload = encoded.strip_prefix("0x").ok_or_else(|| { + ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar {field} must be 0x-prefixed" + ))) + })?; + if payload.len() != expected_len.saturating_mul(2) { + return Err(ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar {field} has invalid encoded length" + )))); + } + let decoded = hex::decode(payload).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar {field} is not valid hex: {e}" + ))) + })?; + if decoded.len() != expected_len { + return Err(ScalarError::CalculateError(anyhow!(format!( + "beacon blob sidecar {field} has invalid decoded length" + )))); + } + Ok(decoded) +} + +fn verify_blob_sidecar( + sidecar: &Value, + expected_versioned_hash: H256, +) -> Result<[u8; MAX_BLOB_TX_PAYLOAD_SIZE], ScalarError> { + let commitment_bytes = decode_beacon_hex(sidecar, "kzg_commitment", 48)?; + let actual_versioned_hash = kzg_to_versioned_hash(&commitment_bytes); + if expected_versioned_hash != actual_versioned_hash { + return Err(ScalarError::CalculateError(anyhow!(format!( + "invalid blob versioned hash: expected {expected_versioned_hash:?}, got {actual_versioned_hash:?}" + )))); + } + + let blob_bytes = decode_beacon_hex(sidecar, "blob", MAX_BLOB_TX_PAYLOAD_SIZE)?; + let proof_bytes = decode_beacon_hex(sidecar, "kzg_proof", 48)?; + let blob = KzgBlob::from_bytes(&blob_bytes).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!("invalid KZG blob encoding: {e}"))) + })?; + let commitment = Bytes48::from_bytes(&commitment_bytes).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!("invalid KZG commitment encoding: {e}"))) + })?; + let proof = Bytes48::from_bytes(&proof_bytes).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!("invalid KZG proof encoding: {e}"))) + })?; + let verified = ethereum_kzg_settings(0) + .verify_blob_kzg_proof(&blob, &commitment, &proof) + .map_err(|e| { + ScalarError::CalculateError(anyhow!(format!("KZG sidecar verification failed: {e}"))) + })?; + if !verified { + return Err(ScalarError::CalculateError(anyhow!( + "KZG sidecar proof does not match blob and commitment" + ))); + } + + blob_bytes.try_into().map_err(|_| { + ScalarError::CalculateError(anyhow!("verified blob has an unexpected byte length")) + }) +} + /// Extract the full batch data from multiple blobs. /// All blobs belong to the same batch: the batch is compressed as a whole, split into /// multiple segments (each at most 4096 * 31 bytes), and then encoded into BLS12-381 @@ -23,76 +113,46 @@ pub(super) fn extract_tx_payload( sidecars: &[Value], ) -> Result, ScalarError> { let num_blobs = indexed_hashes.len(); + let mut sidecars_by_index = BTreeMap::new(); + for sidecar in sidecars { + let index = sidecar_index(sidecar)?; + if sidecars_by_index.insert(index, sidecar).is_some() { + return Err(ScalarError::CalculateError(anyhow!(format!( + "beacon response contains duplicate blob sidecar index {index}" + )))); + } + } + let mut combined_payload = Vec::::new(); for i_h in indexed_hashes { - if let Some(sidecar) = sidecars.iter().find(|sidecar| { - sidecar["index"].as_str().unwrap_or("1000").parse::().unwrap_or(1000) == i_h.index - }) { - let kzg_commitment = sidecar["kzg_commitment"].as_str().ok_or_else(|| { - ScalarError::CalculateError(anyhow!("Failed to fetch kzg commitment from blob")) - })?; - let decoded_commitment: Vec = - hex::decode(kzg_commitment).map_err(|e| ScalarError::CalculateError(e.into()))?; - let actual_versioned_hash = kzg_to_versioned_hash(&decoded_commitment); - - if i_h.hash != actual_versioned_hash { - log::error!( - "expected hash {:?} for blob at index {:?} but got {:?}", - i_h.hash, - i_h.index, - actual_versioned_hash - ); - - return Err(ScalarError::CalculateError(anyhow!(format!( - "Invalid versionedHash for Blob, expected hash {:?} for blob at index {:?} but got {:?}", - i_h.hash, i_h.index, actual_versioned_hash - )))); - } - - let encoded_blob = sidecar["blob"].as_str().ok_or_else(|| { - ScalarError::CalculateError(anyhow!(format!( - "Missing blob value in blob_hash: {:?}", - i_h.hash - ))) - })?; - let decoded_blob = hex::decode(encoded_blob).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "Failed to decode blob, blob_hash: {:?}, err: {}", - i_h.hash, e - ))) - })?; - - if decoded_blob.len() != MAX_BLOB_TX_PAYLOAD_SIZE { - return Err(ScalarError::CalculateError(anyhow!("Invalid length for Blob"))); - } - - let blob_array: [u8; MAX_BLOB_TX_PAYLOAD_SIZE] = decoded_blob.try_into().unwrap(); - let blob_struct = Blob(blob_array); - // Extract the raw payload segment by removing only the BLS12-381 encoding, - // without zstd decompression. - let payload_bytes = blob_struct.get_payload_bytes().map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "Failed to get payload bytes from blob, blob_hash: {:?}, err: {}", - i_h.hash, e - ))) - })?; - combined_payload.extend_from_slice(&payload_bytes); - } else { - return Err(ScalarError::CalculateError(anyhow!(format!( + let sidecar = sidecars_by_index.get(&i_h.index).ok_or_else(|| { + ScalarError::CalculateError(anyhow!(format!( "no blob in response matches desired index: {}", i_h.index - )))); - } + ))) + })?; + let blob_array = verify_blob_sidecar(sidecar, i_h.hash)?; + let blob_struct = MorphBlob(blob_array); + // Extract the raw payload segment by removing only the BLS12-381 encoding, + // without zstd decompression. + let payload_bytes = blob_struct.get_payload_bytes().map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "Failed to get payload bytes from blob, blob_hash: {:?}, err: {}", + i_h.hash, e + ))) + })?; + combined_payload.extend_from_slice(&payload_bytes); } // After concatenation, use detect_zstd_compressed to trim the valid compressed payload // (excluding trailing zero padding), then decompress the batch as a whole. - let compressed_data = Blob::detect_zstd_compressed(combined_payload, num_blobs).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "Failed to detect zstd compressed data from combined blob payload: {}", - e - ))) - })?; + let compressed_data = + MorphBlob::detect_zstd_compressed(combined_payload, num_blobs).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "Failed to detect zstd compressed data from combined blob payload: {}", + e + ))) + })?; decompress_batch(&compressed_data).map_err(|e| { ScalarError::CalculateError(anyhow!(format!( "Failed to decompress combined blob payload: {}", @@ -101,18 +161,20 @@ pub(super) fn extract_tx_payload( }) } -pub fn extract_txn_count(origin_batch: &Vec, last_block_num: u64) -> Option { +pub fn extract_txn_count(origin_batch: &[u8], last_block_num: u64) -> Option { if origin_batch.is_empty() || origin_batch.len() < 8 { return None; } let first_block_num = u64::from_be_bytes(origin_batch[0..8].try_into().unwrap_or_default()); - let block_count = last_block_num - first_block_num + 1; - if origin_batch.len() < 60 * block_count as usize { + let block_count = last_block_num.checked_sub(first_block_num)?.checked_add(1)?; + let block_count = usize::try_from(block_count).ok()?; + let required_len = 60usize.checked_mul(block_count)?; + if origin_batch.len() < required_len { log::error!("invalid blob batch len"); return None; } let mut txn_count_in_batch = 0u64; - for i in 0..block_count as usize { + for i in 0..block_count { let bys = &origin_batch[60 * i + 56..60 * i + 58]; let num_txn = u16::from_be_bytes(bys.try_into().unwrap_or_default()); @@ -129,13 +191,40 @@ pub fn extract_txn_count(origin_batch: &Vec, last_block_num: u64) -> Option< Some(txn_count_in_batch) } -#[derive(Debug, Serialize, Deserialize)] -struct BlockInfo { - block_number: U256, - timestamp: u64, - base_fee: U256, - gas_limit: u64, - num_txs: u64, +#[test] +fn extract_txn_count_rejects_reversed_or_truncated_ranges() { + let mut block = vec![0u8; 60]; + block[..8].copy_from_slice(&10u64.to_be_bytes()); + block[56..58].copy_from_slice(&2u16.to_be_bytes()); + assert_eq!(extract_txn_count(&block, 10), Some(2)); + assert_eq!(extract_txn_count(&block, 9), None); + assert_eq!(extract_txn_count(&block[..59], 10), None); +} + +#[test] +fn forged_sidecar_fails_kzg_verification() { + let settings = ethereum_kzg_settings(0); + let blob = KzgBlob::new([0u8; MAX_BLOB_TX_PAYLOAD_SIZE]); + let commitment = settings.blob_to_kzg_commitment(&blob).unwrap().to_bytes(); + + // The proof is valid, but for a different canonical blob/commitment pair. + // This ensures the negative test reaches the KZG relationship check rather + // than failing only on malformed point encodings. + let mut other_blob_bytes = [0u8; MAX_BLOB_TX_PAYLOAD_SIZE]; + other_blob_bytes[31] = 1; + let other_blob = KzgBlob::new(other_blob_bytes); + let other_commitment = settings.blob_to_kzg_commitment(&other_blob).unwrap().to_bytes(); + let forged_proof = settings.compute_blob_kzg_proof(&other_blob, &other_commitment).unwrap(); + + let sidecar = serde_json::json!({ + "index": "0", + "blob": format!("0x{}", hex::encode(blob.as_ref())), + "kzg_commitment": format!("0x{}", hex::encode(commitment.as_ref())), + "kzg_proof": format!("0x{}", hex::encode(forged_proof.to_bytes().as_ref())), + }); + let expected_hash = kzg_to_versioned_hash(commitment.as_ref()); + let error = verify_blob_sidecar(&sidecar, expected_hash).unwrap_err(); + assert!(error.to_string().contains("does not match")); } #[derive(Debug, Clone)] diff --git a/gas-oracle/app/src/da_scalar/error.rs b/gas-oracle/app/src/da_scalar/error.rs index 5a7b3a05f..ea5946678 100644 --- a/gas-oracle/app/src/da_scalar/error.rs +++ b/gas-oracle/app/src/da_scalar/error.rs @@ -8,4 +8,3 @@ pub enum ScalarError { #[error("{0}")] BeaconNodeError(eyre::Error), } - diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index bbd6d8e7a..d5ef3aeaf 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -1,7 +1,7 @@ -use std::sync::Arc; - -use eyre::anyhow; -use tokio::time::{sleep, Duration}; +use std::{ + collections::{BTreeSet, HashMap, HashSet}, + sync::Arc, +}; use super::{ blob_client::BeaconNode, @@ -10,20 +10,171 @@ use super::{ MAX_BLOB_TX_PAYLOAD_SIZE, }; use crate::{ - abi::{ - gas_price_oracle_abi::GasPriceOracle, - rollup_abi::{CommitBatchCall, Rollup}, - }, + abi::{gas_price_oracle_abi::GasPriceOracle, rollup_abi::Rollup}, metrics::ORACLE_SERVICE_METRICS, + rollup_compat::{ + decode_batch_data_input, resolve_canonical_commit, CanonicalCommit, SubmissionKind, + LOG_QUERY_RANGE, + }, signer::send_transaction, }; -use ethers::{abi::AbiDecode, prelude::*, utils::hex}; +use ethers::{ + prelude::*, + utils::{hex, keccak256}, +}; +use eyre::anyhow; use remote_signer_client::SignerClient; use serde_json::Value; const PRECISION: u64 = 10u64.pow(9); const MAX_COMMIT_SCALAR: u64 = 10u64.pow(9 + 6); const MAX_BLOB_SCALAR: u64 = 10u64.pow(9 + 2); +const SAMPLE_LOOKBACK_BLOCKS: u64 = 100; +const ZERO_VERSIONED_HASH: H256 = H256([ + 0x01, 0x06, 0x57, 0xf3, 0x75, 0x54, 0xc7, 0x81, 0x40, 0x2a, 0x22, 0x91, 0x7d, 0xee, 0x2f, 0x75, + 0xde, 0xf7, 0xab, 0x96, 0x6d, 0x7b, 0x77, 0x09, 0x05, 0x39, 0x8e, 0xba, 0x3c, 0x44, 0x40, 0x14, +]); + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +struct BlobSource { + transaction_hash: TxHash, + block_number: U64, + block_hash: H256, + transaction_index: U64, + blob_hashes: Vec, +} + +type HistoricalCommitIndex = HashMap>; + +fn index_commit_logs(logs: Vec) -> HistoricalCommitIndex { + let mut index = HistoricalCommitIndex::new(); + for log in logs { + if log.removed.unwrap_or_default() { + continue; + } + let Some(topic) = log.topics.get(1) else { + continue; + }; + let batch_index = U256::from_big_endian(topic.as_bytes()); + if batch_index > U256::from(u64::MAX) { + continue; + } + index.entry(batch_index.as_u64()).or_default().push(log); + } + index +} + +fn batch_indices_from_commit_logs(logs: &[Log], max_batch_index: u64) -> BTreeSet { + logs.iter() + .filter(|log| !log.removed.unwrap_or_default()) + .filter_map(|log| log.topics.get(1)) + .filter_map(|topic| { + let value = U256::from_big_endian(topic.as_bytes()); + (value <= U256::from(max_batch_index)).then(|| value.as_u64()) + }) + .filter(|index| *index > 0) + .collect() +} + +fn ensure_snapshot_hash(expected: H256, actual: Option) -> Result<(), ScalarError> { + if actual != Some(expected) { + return Err(ScalarError::Error(anyhow!( + "finalized snapshot hash changed; discard the complete DA sample round" + ))); + } + Ok(()) +} + +fn transaction_blob_hashes(transaction: &Transaction) -> Vec { + transaction + .other + .get_with("blobVersionedHashes", serde_json::from_value::>) + .unwrap_or(Ok(Vec::new())) + .unwrap_or_default() +} + +fn receipt_matches_source(receipt: &TransactionReceipt, source: &BlobSource) -> bool { + receipt.transaction_hash == source.transaction_hash + && receipt.block_number == Some(source.block_number) + && receipt.block_hash == Some(source.block_hash) + && receipt.transaction_index == source.transaction_index +} + +fn blob_commitment(version: u8, hashes: &[H256]) -> Result { + match version { + 0 | 1 if hashes.len() == 1 => Ok(hashes[0]), + 0 | 1 => Err(ScalarError::Error(anyhow!(format!( + "legacy batch must have exactly one blob, got {}", + hashes.len() + )))), + 2 if !hashes.is_empty() => { + let bytes: Vec = + hashes.iter().flat_map(|hash| hash.as_bytes().iter().copied()).collect(); + Ok(H256::from(keccak256(bytes))) + } + 2 => Err(ScalarError::Error(anyhow!("V2 batch has no blob"))), + _ => Err(ScalarError::Error(anyhow!(format!("unsupported batch version {version}")))), + } +} + +fn validate_fresh_blob_commitment( + stored_commitment: H256, + transaction_commitment: H256, +) -> Result<(), ScalarError> { + // Rollup garbage-collects the mapping after successor finalization. A + // direct canonical blob transaction remains a stable source even when the + // snapshot getter has already returned zero. + if !stored_commitment.is_zero() && stored_commitment != transaction_commitment { + return Err(ScalarError::Error(anyhow!(format!( + "canonical blob commitment mismatch: stored={stored_commitment:?}, tx={transaction_commitment:?}" + )))); + } + Ok(()) +} + +fn recover_gc_commitment(snapshot: H256, canonical_block: H256) -> H256 { + if snapshot.is_zero() { + canonical_block + } else { + snapshot + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum BloblessDisposition { + ExcludeMissing, + ExcludeZero, + ResolveStored(H256), +} + +fn classify_blobless_submission( + version: u8, + kind: SubmissionKind, + pre_submitter: bool, + stored_commitment: H256, +) -> Result { + if kind == SubmissionKind::CommitBatch && !pre_submitter { + return Err(ScalarError::Error(anyhow!( + "current canonical commitBatch has no blob; refusing zero-data scalar sample" + ))); + } + + if version <= 1 && stored_commitment == ZERO_VERSIONED_HASH { + // Before the Submitter cutover, commitBatch legitimately accepted a + // V0/V1 transaction without a blob and stored ZERO_VERSIONED_HASH. + // Permissionless proof/state submissions can also reuse that value. + return Ok(BloblessDisposition::ExcludeZero); + } + if stored_commitment.is_zero() { + return Ok(BloblessDisposition::ExcludeMissing); + } + if kind == SubmissionKind::CommitBatch { + return Err(ScalarError::Error(anyhow!( + "legacy canonical commitBatch is blobless with a non-zero stored commitment" + ))); + } + Ok(BloblessDisposition::ResolveStored(stored_commitment)) +} // Main struct to manage overhead information pub struct ScalarUpdater { @@ -33,6 +184,7 @@ pub struct ScalarUpdater { ext_signer: Option, l1_rollup: Rollup>, // Rollup object for L1 beacon_node: BeaconNode, // Beacon node for blockchain + l1_rollup_deploy_block: u64, gas_threshold: u64, commit_scalar_buffer: u64, blob_scalar_buffer: u64, @@ -50,6 +202,7 @@ impl ScalarUpdater { ext_signer: Option, l1_rollup: Rollup>, l1_beacon_rpc: String, + l1_rollup_deploy_block: u64, gas_threshold: u64, commit_scalar_buffer: u64, blob_scalar_buffer: u64, @@ -67,6 +220,7 @@ impl ScalarUpdater { ext_signer, l1_rollup, beacon_node, + l1_rollup_deploy_block, gas_threshold, commit_scalar_buffer, blob_scalar_buffer, @@ -79,27 +233,47 @@ impl ScalarUpdater { /// Calculate the user's average cost of the latest rollup and set it to the GasPriceOrale /// contract on the L2 network. pub async fn update(&mut self) -> Result<(), ScalarError> { - // Step1. fetch latest batches and calculate scalar. - let latest = self.l1_provider.get_block_number().await.map_err(|e| { - ScalarError::Error(anyhow!(format!( - "overhead.l1_provider.get_block_number error: {:#?}", - e - ))) - })?; - let start = if latest > U64::from(100) { - latest - U64::from(100) //100 + // Step1. Pin all reads to one finalized L1 block. A latest-head sample + // can be reorged after the oracle has already written its L2 scalar. + let snapshot = self + .l1_provider + .get_block(BlockNumber::Finalized) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "overhead.l1_provider.get finalized block error: {:#?}", + e + ))) + })? + .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block is unavailable")))?; + let snapshot_number = snapshot + .number + .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block has no number")))?; + let snapshot_hash = snapshot + .hash + .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block has no hash")))?; + if self.l1_rollup_deploy_block == 0 + || self.l1_rollup_deploy_block > snapshot_number.as_u64() + { + return Err(ScalarError::Error(anyhow!(format!( + "configured Rollup deployment block {} is outside finalized snapshot 1..={}", + self.l1_rollup_deploy_block, snapshot_number + )))); + } + let start = if snapshot_number > U64::from(SAMPLE_LOOKBACK_BLOCKS) { + snapshot_number - U64::from(SAMPLE_LOOKBACK_BLOCKS) } else { U64::from(1) }; - let (mut commit_scalar, mut blob_scalar) = match self.calculate_scalar(start.as_u64()).await - { - Ok(Some(scalar)) => scalar, - Ok(None) => { - return Ok(()); - } - Err(e) => return Err(e), - }; + let (mut commit_scalar, mut blob_scalar) = + match self.calculate_scalar(start.as_u64(), snapshot_number, snapshot_hash).await { + Ok(Some(scalar)) => scalar, + Ok(None) => { + return Ok(()); + } + Err(e) => return Err(e), + }; // Step2. fetch current scalar on l2. let current_commit_scalar: U256 = self.l2_oracle.commit_scalar().await.map_err(|e| { @@ -170,84 +344,491 @@ impl ScalarUpdater { need_update } - async fn calculate_scalar(&mut self, start: u64) -> Result, ScalarError> { - let filter = self + async fn calculate_scalar( + &mut self, + start: u64, + snapshot_number: U64, + snapshot_hash: H256, + ) -> Result, ScalarError> { + let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); + let last_batch_index = self .l1_rollup - .commit_batch_filter() - .filter - .from_block(start) - .address(self.l1_rollup.address()); + .last_committed_batch_index() + .block(block_id) + .call() + .await + .map_err(|e| ScalarError::Error(anyhow!(format!("query last committed batch: {e:?}"))))? + .as_u64(); + if last_batch_index == 0 { + log::warn!("no non-genesis batch exists at finalized L1 snapshot, skip update"); + return Ok(None); + } - let mut logs = self.l1_provider.get_logs(&filter).await.map_err(|e| { - ScalarError::Error(anyhow!(format!("overhead.l1_provider.get_logs error: {:#?}", e))) - })?; + let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); + let candidate_logs = self + .l1_provider + .get_logs( + &Filter::new() + .address(self.l1_rollup.address()) + .from_block(start) + .to_block(snapshot_number) + .topic0(commit_topic), + ) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!("query finalized Commit window: {e:?}"))) + })?; + let batch_indices = batch_indices_from_commit_logs(&candidate_logs, last_batch_index); + if batch_indices.is_empty() { + log::warn!("no Commit event exists in the finalized DA sample window"); + return Ok(None); + } + + let mut seen_sources = HashSet::new(); + let mut commit_scalar_sum = 0u128; + let mut blob_scalar_sum = 0u128; + let mut sample_count = 0u128; + let mut historical_commits = None; + + for batch_index in batch_indices { + let canonical = resolve_canonical_commit( + &self.l1_rollup, + &self.l1_provider, + batch_index, + start, + snapshot_number, + ) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "resolve canonical commit for batch {batch_index}: {e:#}" + ))) + })?; + let Some(canonical) = canonical else { + // The window may contain a Commit that was canonically reverted + // before the pinned snapshot. It contributes no DA sample. + continue; + }; - log::debug!("overhead.l1_provider.submit_batches.get_logs.len ={:#?}", logs.len()); + let canonical_tx = self.load_commit_transaction(canonical).await?; + let input = decode_batch_data_input(canonical_tx.input.as_ref()).map_err(|e| { + ScalarError::Error(anyhow!(format!( + "decode canonical commit {:?}: {e:#}", + canonical.transaction_hash + ))) + })?; + let blob_source = self + .resolve_blob_source( + batch_index, + canonical, + &canonical_tx, + input.version, + input.kind, + input.pre_submitter, + snapshot_number, + snapshot_hash, + &mut historical_commits, + ) + .await?; + let Some(blob_source) = blob_source else { + ORACLE_SERVICE_METRICS.da_sample_exclusions.inc(); + log::warn!( + "canonical batch {} has no verifiable real DA blob source; excluded", + batch_index + ); + continue; + }; + if !seen_sources.insert(blob_source.clone()) { + ORACLE_SERVICE_METRICS.da_sample_exclusions.inc(); + log::warn!( + "duplicate DA blob source {:?} in finalized window; counted once", + blob_source.transaction_hash + ); + continue; + } + + let (commit_scalar, blob_scalar) = self + .calculate_from_rollup(blob_source, input.last_block_number) + .await + .inspect_err(|_| { + log::info!( + "scalar is unavailable, canonical_tx_hash ={:#?}", + canonical.transaction_hash + ); + })?; + commit_scalar_sum += u128::from(commit_scalar); + blob_scalar_sum += u128::from(blob_scalar); + sample_count += 1; + } - logs.retain(|x| x.transaction_hash.is_some() && x.block_number.is_some()); - if logs.is_empty() { - log::warn!("rollup logs for the last 100 blocks of l1 is empty, skip update"); + let after = self + .l1_provider + .get_block(snapshot_number) + .await + .map_err(|e| ScalarError::Error(anyhow!(format!("recheck finalized snapshot: {e:?}"))))? + .ok_or_else(|| ScalarError::Error(anyhow!("finalized snapshot disappeared")))?; + ensure_snapshot_hash(snapshot_hash, after.hash)?; + if sample_count == 0 { return Ok(None); } - let log = logs.iter().max_by_key(|log| log.block_number.unwrap()).ok_or_else(|| { - ScalarError::Error(anyhow!(format!( - "no submit batches logs, start blocknum ={:#?}", - start - ))) - })?; + let commit_scalar = u64::try_from(commit_scalar_sum / sample_count) + .map_err(|_| ScalarError::Error(anyhow!("averaged commit scalar overflow")))?; + let blob_scalar = u64::try_from(blob_scalar_sum / sample_count) + .map_err(|_| ScalarError::Error(anyhow!("averaged blob scalar overflow")))?; + Ok(Some((commit_scalar, blob_scalar))) + } + + async fn load_commit_transaction( + &self, + commit: CanonicalCommit, + ) -> Result { + let transaction = self + .l1_provider + .get_transaction(commit.transaction_hash) + .await + .map_err(|e| ScalarError::Error(anyhow!(format!("get commit transaction: {e:?}"))))? + .ok_or_else(|| { + ScalarError::Error(anyhow!(format!( + "commit transaction {:?} is unavailable", + commit.transaction_hash + ))) + })?; + if transaction.to != Some(self.l1_rollup.address()) + || transaction.block_number != Some(commit.identity.block_number.into()) + || transaction.block_hash != Some(commit.block_hash) + || transaction.transaction_index != Some(commit.identity.transaction_index.into()) + { + return Err(ScalarError::Error(anyhow!(format!( + "commit transaction {:?} moved to a different block", + commit.transaction_hash + )))); + } + Ok(transaction) + } + + async fn load_canonical_block_commitment( + &self, + batch_index: u64, + canonical: CanonicalCommit, + ) -> Result { + if canonical.identity.block_number < self.l1_rollup_deploy_block { + return Err(ScalarError::Error(anyhow!(format!( + "canonical commit block {} predates configured Rollup deployment block {}", + canonical.identity.block_number, self.l1_rollup_deploy_block + )))); + } + + let canonical_number = U64::from(canonical.identity.block_number); + let before = self + .l1_provider + .get_block(BlockNumber::Number(canonical_number)) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "load canonical commit block before historical getter: {e:?}" + ))) + })? + .ok_or_else(|| ScalarError::Error(anyhow!("canonical commit block disappeared")))?; + if before.hash != Some(canonical.block_hash) { + return Err(ScalarError::Error(anyhow!( + "canonical commit block hash changed before historical getter" + ))); + } + + // Use the block hash, rather than an unpinned number, for the historical + // eth_call. This recovers the mapping value before later finalization GC. + let commitment: H256 = self + .l1_rollup + .batch_blob_versioned_hashes(U256::from(batch_index)) + .block(BlockId::Hash(canonical.block_hash)) + .call() + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "query stored blob commitment at canonical commit block: {e:?}" + ))) + })? + .into(); + + let after = self + .l1_provider + .get_block(BlockNumber::Number(canonical_number)) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "recheck canonical commit block after historical getter: {e:?}" + ))) + })? + .ok_or_else(|| ScalarError::Error(anyhow!("canonical commit block disappeared")))?; + if after.hash != Some(canonical.block_hash) { + return Err(ScalarError::Error(anyhow!( + "canonical commit block hash changed during historical getter" + ))); + } + Ok(commitment) + } + + async fn load_historical_commit_index( + &self, + snapshot_number: U64, + ) -> Result { + if self.l1_rollup_deploy_block > snapshot_number.as_u64() { + return Err(ScalarError::Error(anyhow!( + "Rollup deployment block is newer than the finalized snapshot" + ))); + } - #[allow(clippy::manual_inspect)] - let (commit_scalar, blob_scalar) = self - .calculate_from_rollup(log.transaction_hash.unwrap(), log.block_number.unwrap()) + // Replay CommitBatch once per scalar round and share the resulting + // index between every stored-source batch. Replaying the entire chain + // separately for each batch multiplies RPC load by the sample count. + let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); + let mut logs = Vec::new(); + let mut from = self.l1_rollup_deploy_block; + let snapshot = snapshot_number.as_u64(); + loop { + let to = from.saturating_add(LOG_QUERY_RANGE - 1).min(snapshot); + logs.extend( + self.l1_provider + .get_logs( + &Filter::new() + .address(self.l1_rollup.address()) + .from_block(from) + .to_block(to) + .topic0(commit_topic), + ) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!( + "query historical blob-source commits in {from}..={to}: {e:?}" + ))) + })?, + ); + if to == snapshot { + break; + } + from = to + .checked_add(1) + .ok_or_else(|| ScalarError::Error(anyhow!("commit replay block overflow")))?; + } + Ok(index_commit_logs(logs)) + } + + #[allow(clippy::too_many_arguments)] + async fn resolve_blob_source( + &self, + batch_index: u64, + canonical: CanonicalCommit, + canonical_tx: &Transaction, + version: u8, + kind: SubmissionKind, + pre_submitter: bool, + snapshot_number: U64, + snapshot_hash: H256, + historical_commits: &mut Option, + ) -> Result, ScalarError> { + let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); + let snapshot_commitment: H256 = self + .l1_rollup + .batch_blob_versioned_hashes(U256::from(batch_index)) + .block(block_id) + .call() .await .map_err(|e| { - log::info!( - "scalar is none, skip update, tx_hash ={:#?}", - log.transaction_hash.unwrap() + ScalarError::Error(anyhow!(format!("query stored blob commitment: {e:?}"))) + })? + .into(); + + let current_hashes = transaction_blob_hashes(canonical_tx); + if !current_hashes.is_empty() { + let actual_commitment = blob_commitment(version, ¤t_hashes)?; + validate_fresh_blob_commitment(snapshot_commitment, actual_commitment)?; + return Ok(Some(BlobSource { + transaction_hash: canonical.transaction_hash, + block_number: canonical.identity.block_number.into(), + block_hash: canonical.block_hash, + transaction_index: canonical.identity.transaction_index.into(), + blob_hashes: current_hashes, + })); + } + + // A post-cutover commitBatch is required by the Rollup contract to + // carry a blob. Keep that invariant fail-closed even if storage was GC'd. + if kind == SubmissionKind::CommitBatch && !pre_submitter { + return classify_blobless_submission(version, kind, pre_submitter, snapshot_commitment) + .map(|_| None); + } + + let canonical_block_commitment = if snapshot_commitment.is_zero() { + self.load_canonical_block_commitment(batch_index, canonical).await? + } else { + snapshot_commitment + }; + let expected_commitment = + recover_gc_commitment(snapshot_commitment, canonical_block_commitment); + match classify_blobless_submission(version, kind, pre_submitter, expected_commitment)? { + BloblessDisposition::ExcludeZero => { + log::warn!( + "canonical batch {} is a legal V0/V1 blobless ZERO_VERSIONED_HASH submission; excluded from DA scalar sampling", + batch_index ); - e - })?; + return Ok(None); + } + BloblessDisposition::ExcludeMissing => { + log::warn!( + "batch {} stored blob commitment is zero at both finalized snapshot and canonical commit block; excluded and alert", + batch_index + ); + return Ok(None); + } + BloblessDisposition::ResolveStored(commitment) => { + debug_assert_eq!(commitment, expected_commitment); + } + } - Ok(Some((commit_scalar, blob_scalar))) + // Stored-source recommits intentionally look *before* the last Revert. + // Canonical filtering here would discard the original blob transaction. + if historical_commits.is_none() { + *historical_commits = Some(self.load_historical_commit_index(snapshot_number).await?); + } + let mut candidates = historical_commits + .as_ref() + .and_then(|index| index.get(&batch_index)) + .cloned() + .unwrap_or_default(); + candidates.retain(|log| { + log.block_number + .is_some_and(|number| number.as_u64() <= canonical.identity.block_number) + }); + candidates.sort_by_key(|log| { + ( + log.block_number.unwrap_or_default(), + log.transaction_index.unwrap_or_default(), + log.log_index.unwrap_or_default(), + ) + }); + + for candidate in candidates.into_iter().rev() { + let Some(transaction_hash) = candidate.transaction_hash else { + continue; + }; + if transaction_hash == canonical.transaction_hash { + continue; + } + let Some(block_number) = candidate.block_number else { + continue; + }; + let Some(block_hash) = candidate.block_hash else { + continue; + }; + let Some(transaction_index) = candidate.transaction_index else { + continue; + }; + let Some(transaction) = + self.l1_provider.get_transaction(transaction_hash).await.map_err(|e| { + ScalarError::Error(anyhow!(format!("get blob-source transaction: {e:?}"))) + })? + else { + continue; + }; + if transaction.to != Some(self.l1_rollup.address()) + || transaction.block_number != Some(block_number) + || transaction.block_hash != Some(block_hash) + || transaction.transaction_index != Some(transaction_index) + { + return Err(ScalarError::Error(anyhow!(format!( + "blob-source transaction {transaction_hash:?} changed block identity" + )))); + } + let Ok(candidate_input) = decode_batch_data_input(transaction.input.as_ref()) else { + continue; + }; + if candidate_input.version != version { + continue; + } + let hashes = transaction_blob_hashes(&transaction); + if hashes.is_empty() { + continue; + } + if blob_commitment(candidate_input.version, &hashes)? != expected_commitment { + continue; + } + + let after = self + .l1_provider + .get_block(snapshot_number) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!("recheck finalized snapshot: {e:?}"))) + })? + .ok_or_else(|| ScalarError::Error(anyhow!("finalized snapshot disappeared")))?; + ensure_snapshot_hash(snapshot_hash, after.hash)?; + log::info!( + "resolved stored blob source: batch={}, canonical_tx={:?}, source_tx={:?}, source_block={}, blobs={}", + batch_index, + canonical.transaction_hash, + transaction_hash, + block_number, + hashes.len() + ); + return Ok(Some(BlobSource { + transaction_hash, + block_number, + block_hash, + transaction_index, + blob_hashes: hashes, + })); + } + + log::warn!( + "no historical blob source matches batch {} commitment {:?}; exclude and alert", + batch_index, + expected_commitment + ); + Ok(None) } async fn calculate_from_rollup( &mut self, - tx_hash: TxHash, - block_num: U64, + blob_source: BlobSource, + last_block_number: u64, ) -> Result<(u64, u64), ScalarError> { //Step1. get_data_from_blob let (l2_data_len, num_blobs, l2_txn) = - self.get_data_from_blob(tx_hash, block_num).await.map_err(|e| { + self.get_data_from_blob(&blob_source, last_block_number).await.map_err(|e| { log::error!("get_data_from_blob error: {:#?}", e); e })?; - let blob_tx_receipt = self + let source_tx_receipt = self .l1_provider - .get_transaction_receipt(tx_hash) + .get_transaction_receipt(blob_source.transaction_hash) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( - "l1 get transaction receipt return none, tx_hash= {:#?}", - tx_hash + "l1 get source transaction receipt return none, tx_hash= {:#?}", + blob_source.transaction_hash ))) })?; + if !receipt_matches_source(&source_tx_receipt, &blob_source) { + return Err(ScalarError::Error(anyhow!( + "original blob source receipt identity mismatch" + ))); + } // rollup_gas_used - let rollup_gas_used = blob_tx_receipt.gas_used.unwrap_or_default(); + let rollup_gas_used = source_tx_receipt.gas_used.unwrap_or_default(); if rollup_gas_used.is_zero() { return Err(ScalarError::Error(anyhow!(format!( "blob tx calldata gas_used is none or 0, tx_hash = {:#?}", - tx_hash + blob_source.transaction_hash )))); } //Step2. Calculate scalar - let commit_scalar = (rollup_gas_used.as_u64() + self.finalize_batch_gas_used) * PRECISION / - l2_txn.max(self.txn_per_batch); + let commit_scalar = (rollup_gas_used.as_u64() + self.finalize_batch_gas_used) * PRECISION + / l2_txn.max(self.txn_per_batch); let blob_scalar = if l2_data_len > 0 { num_blobs.max(1) * MAX_BLOB_TX_PAYLOAD_SIZE as u64 * PRECISION / l2_data_len } else { @@ -270,84 +851,85 @@ impl ScalarUpdater { async fn get_data_from_blob( &self, - tx_hash: TxHash, - block_num: U64, + source: &BlobSource, + last_block_num: u64, ) -> Result<(u64, u64, u64), ScalarError> { let blob_tx = self .l1_provider - .get_transaction(tx_hash) + .get_transaction(source.transaction_hash) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( "l1 get transaction return none, tx_hash: {:#?}", - tx_hash + source.transaction_hash ))) })?; + if blob_tx.to != Some(self.l1_rollup.address()) + || blob_tx.block_number != Some(source.block_number) + || blob_tx.block_hash != Some(source.block_hash) + || blob_tx.transaction_index != Some(source.transaction_index) + { + return Err(ScalarError::Error(anyhow!( + "blob source transaction changed block identity" + ))); + } let blob_block = self .l1_provider - .get_block_with_txs(BlockNumber::Number(block_num)) + .get_block_with_txs(BlockNumber::Number(source.block_number)) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( "l1 get block info return none, block_num: {:#?}", - block_num + source.block_number ))) })?; + if blob_block.hash != Some(source.block_hash) { + return Err(ScalarError::Error(anyhow!( + "blob source block hash changed before sidecar lookup" + ))); + } let indexed_hashes = data_and_hashes_from_txs(&blob_block.transactions, &blob_tx); if indexed_hashes.is_empty() { - log::info!("no blob in this batch, batch_tx_hash: {:#?}", tx_hash); - return Ok((0, 0, 0)); + return Err(ScalarError::Error(anyhow!(format!( + "resolved blob source {:?} has no blob positions", + source.transaction_hash + )))); + } + let actual_hashes: Vec = indexed_hashes.iter().map(|item| item.hash).collect(); + if actual_hashes != source.blob_hashes { + return Err(ScalarError::Error(anyhow!( + "blob positions changed between source resolution and sidecar lookup" + ))); } - // Waiting for the next L1 block to be produced. - let next_block_num = block_num + 1; - // Max delay 5 * 3 = 15 secs - let mut retry_times = 5; - let prev_beacon_root = loop { - let blk_info = self.l1_provider.get_block(BlockNumber::Number(next_block_num)).await; - if let Ok(Some(info)) = blk_info { - if let Some(beacon_blk_root) = info.parent_beacon_block_root { - break beacon_blk_root; - } else { - return Err(ScalarError::Error(anyhow!(format!( - "next block info's pre_beacon_root is none, block number: {:?}", - next_block_num - )))); - } - } else if retry_times > 0 { - retry_times -= 1; - sleep(Duration::from_secs(3)).await; - - log::info!( - "request next block info, retry times= {:?}, block number: {:?}", - retry_times, - next_block_num - ); - continue; - } else { - return Err(ScalarError::Error(anyhow!(format!( - "maximum number of requests next block info reached: {:?}, block number:{:?}", - retry_times, next_block_num - )))); - } - }; - - // Parse last_block_num - if blob_tx.input.is_empty() { - log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", tx_hash); - return Err(ScalarError::Error(anyhow!(format!("commitBatch tx.input empty")))); + // The sample is finalized, so the following block (whose parent beacon + // root addresses this execution block's sidecars) must already exist. + let next_block_num = + U64::from( + source.block_number.as_u64().checked_add(1).ok_or_else(|| { + ScalarError::Error(anyhow!("blob source block number overflow")) + })?, + ); + let next_block = self + .l1_provider + .get_block(BlockNumber::Number(next_block_num)) + .await + .map_err(|e| ScalarError::Error(anyhow!(format!("get next L1 block: {e:?}"))))? + .ok_or_else(|| ScalarError::Error(anyhow!("next finalized L1 block is unavailable")))?; + if next_block.parent_hash != source.block_hash { + return Err(ScalarError::Error(anyhow!( + "next L1 block is not the canonical child of the blob source block" + ))); } - let param = if let Ok(_param) = CommitBatchCall::decode(&blob_tx.input) { - _param - } else { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); - return Err(ScalarError::Error(anyhow!(format!("decode commitBatch tx.input error",)))); - }; - let last_block_num: u64 = param.batch_data_input.last_block_number; + let prev_beacon_root = next_block.parent_beacon_block_root.ok_or_else(|| { + ScalarError::Error(anyhow!(format!( + "next block has no parent beacon root, block number: {next_block_num:?}" + ))) + })?; let indexes: Vec = indexed_hashes.iter().map(|item| item.index).collect(); let sidecars_rt = self @@ -358,14 +940,14 @@ impl ScalarUpdater { let sidecars: &Vec = sidecars_rt["data"].as_array().ok_or_else(|| { ScalarError::Error(anyhow!(format!( "blob_sidecars is none, blk_num: {:?}, blk_root: {:?}", - block_num, prev_beacon_root + source.block_number, prev_beacon_root ))) })?; if sidecars.is_empty() { return Err(ScalarError::Error(anyhow!(format!( "blob_sidecars is empty, blk_num: {:?}, blk_root: {:?}", - block_num, prev_beacon_root + source.block_number, prev_beacon_root )))); } @@ -377,7 +959,11 @@ impl ScalarUpdater { let origin_batch = extract_tx_payload(indexed_hashes, sidecars)?; let batch_size = origin_batch.len() as u64; - let txn_count = extract_txn_count(&origin_batch, last_block_num).unwrap_or_default(); + let txn_count = extract_txn_count(&origin_batch, last_block_num).ok_or_else(|| { + ScalarError::CalculateError(anyhow!( + "blob payload block range does not match canonical lastBlockNumber" + )) + })?; Ok((batch_size, num_blobs, txn_count)) } @@ -389,6 +975,142 @@ mod tests { use super::*; use std::{env::var, str::FromStr, sync::Arc}; + #[test] + fn v2_blob_commitment_preserves_order() { + let a = H256::from_low_u64_be(1); + let b = H256::from_low_u64_be(2); + assert_ne!(blob_commitment(2, &[a, b]).unwrap(), blob_commitment(2, &[b, a]).unwrap()); + assert!(blob_commitment(2, &[]).is_err()); + assert!(blob_commitment(1, &[a, b]).is_err()); + } + + #[test] + fn fresh_blob_survives_mapping_gc_but_not_a_nonzero_mismatch() { + let actual = H256::from_low_u64_be(7); + assert!(validate_fresh_blob_commitment(H256::zero(), actual).is_ok()); + assert!(validate_fresh_blob_commitment(actual, actual).is_ok()); + assert!(validate_fresh_blob_commitment(H256::from_low_u64_be(8), actual).is_err()); + } + + #[test] + fn mapping_gc_recovery_prefers_snapshot_then_canonical_block() { + let snapshot = H256::from_low_u64_be(1); + let historical = H256::from_low_u64_be(2); + assert_eq!(recover_gc_commitment(snapshot, historical), snapshot); + assert_eq!(recover_gc_commitment(H256::zero(), historical), historical); + assert_eq!(recover_gc_commitment(H256::zero(), H256::zero()), H256::zero()); + } + + #[test] + fn zero_blobless_classification_preserves_legacy_but_rejects_current_commit_batch() { + assert_eq!( + classify_blobless_submission( + 0, + SubmissionKind::CommitBatch, + true, + ZERO_VERSIONED_HASH, + ) + .unwrap(), + BloblessDisposition::ExcludeZero + ); + assert_eq!( + classify_blobless_submission( + 1, + SubmissionKind::CommitBatchWithProof, + false, + ZERO_VERSIONED_HASH, + ) + .unwrap(), + BloblessDisposition::ExcludeZero + ); + assert_eq!( + classify_blobless_submission(1, SubmissionKind::CommitState, false, H256::zero(),) + .unwrap(), + BloblessDisposition::ExcludeMissing + ); + assert!(classify_blobless_submission( + 1, + SubmissionKind::CommitBatch, + false, + ZERO_VERSIONED_HASH, + ) + .is_err()); + } + + #[test] + fn blob_source_dedup_uses_full_stable_identity() { + let source = BlobSource { + transaction_hash: H256::from_low_u64_be(1), + block_number: 10.into(), + block_hash: H256::from_low_u64_be(10), + transaction_index: 0.into(), + blob_hashes: vec![H256::from_low_u64_be(11)], + }; + let mut sources = HashSet::new(); + assert!(sources.insert(source.clone())); + assert!(!sources.insert(source.clone())); + + let mut orphan_replacement = source; + orphan_replacement.block_hash = H256::from_low_u64_be(12); + assert!(sources.insert(orphan_replacement)); + } + + #[test] + fn source_receipt_must_match_full_stable_identity() { + let source = BlobSource { + transaction_hash: H256::from_low_u64_be(1), + block_number: 10.into(), + block_hash: H256::from_low_u64_be(10), + transaction_index: 2.into(), + blob_hashes: vec![H256::from_low_u64_be(11)], + }; + let mut receipt = TransactionReceipt { + transaction_hash: source.transaction_hash, + block_number: Some(source.block_number), + block_hash: Some(source.block_hash), + transaction_index: source.transaction_index, + ..Default::default() + }; + assert!(receipt_matches_source(&receipt, &source)); + receipt.block_hash = Some(H256::from_low_u64_be(12)); + assert!(!receipt_matches_source(&receipt, &source)); + } + + #[test] + fn commit_window_indices_are_unique_and_bounded() { + let topic0 = H256::from_low_u64_be(1); + let make_log = |index: u64| Log { + topics: vec![topic0, H256::from_low_u64_be(index)], + ..Default::default() + }; + let removed = Log { removed: Some(true), ..make_log(2) }; + let indices = batch_indices_from_commit_logs( + &[make_log(1), make_log(1), removed, make_log(3), make_log(9)], + 3, + ); + assert_eq!(indices.into_iter().collect::>(), vec![1, 3]); + } + + #[test] + fn historical_commit_replay_is_indexed_once_by_batch() { + let make_log = |index: u64| Log { + topics: vec![H256::zero(), H256::from_low_u64_be(index)], + ..Default::default() + }; + let removed = Log { removed: Some(true), ..make_log(2) }; + let index = index_commit_logs(vec![make_log(1), make_log(1), make_log(2), removed]); + assert_eq!(index.get(&1).unwrap().len(), 2); + assert_eq!(index.get(&2).unwrap().len(), 1); + } + + #[test] + fn changed_snapshot_hash_fails_closed() { + let expected = H256::from_low_u64_be(1); + assert!(ensure_snapshot_hash(expected, Some(expected)).is_ok()); + assert!(ensure_snapshot_hash(expected, Some(H256::from_low_u64_be(2))).is_err()); + assert!(ensure_snapshot_hash(expected, None).is_err()); + } + #[tokio::test] #[ignore] async fn test_calculate_from_current_rollup() { @@ -436,6 +1158,7 @@ mod tests { .expect("Cannot detect GAS_ORACLE_L1_BEACON_RPC env empty") .parse() .expect("Cannot parse GAS_ORACLE_L1_BEACON_RPC env var empty"), + 1u64, gas_threshold, 0u64, 0u64, @@ -443,8 +1166,16 @@ mod tests { 50u64, ); - let latest_overhead = - overhead.calculate_from_rollup(rollup_tx_hash, rollup_tx_block_num).await; + let source_tx = + overhead.l1_provider.get_transaction(rollup_tx_hash).await.unwrap().unwrap(); + let source = BlobSource { + transaction_hash: rollup_tx_hash, + block_number: rollup_tx_block_num, + block_hash: source_tx.block_hash.unwrap(), + transaction_index: source_tx.transaction_index.unwrap(), + blob_hashes: transaction_blob_hashes(&source_tx), + }; + let latest_overhead = overhead.calculate_from_rollup(source, 0).await; log::info!("latest_overhead: {:#?}", latest_overhead); } diff --git a/gas-oracle/app/src/da_scalar/mod.rs b/gas-oracle/app/src/da_scalar/mod.rs index ae0ed3313..ddc6862df 100644 --- a/gas-oracle/app/src/da_scalar/mod.rs +++ b/gas-oracle/app/src/da_scalar/mod.rs @@ -4,7 +4,7 @@ mod calculate; mod error; #[allow(clippy::module_inception)] pub mod l1_scalar; -mod zstd_util; mod typed_tx; +mod zstd_util; const MAX_BLOB_TX_PAYLOAD_SIZE: usize = 131072; // 131072 = 4096 * 32 = 1024 * 4 * 32 = 128kb diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index 74655abb3..ebff1bfed 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -4,7 +4,6 @@ use crate::{ l1_base_fee::BaseFeeUpdater, read_parse_env, }; -use remote_signer_client::SignerClient; use ethers::{ prelude::*, providers::{Http, Provider}, @@ -12,6 +11,7 @@ use ethers::{ types::Address, }; use eyre::anyhow; +use remote_signer_client::SignerClient; use std::{env::var, error::Error, str::FromStr, sync::Arc, time::Duration}; use tokio::time::sleep; @@ -31,6 +31,7 @@ struct Config { interval: u64, overhead_interval: u64, l1_rollup_address: Address, + l1_rollup_deploy_block: u64, l2_oracle_address: Address, private_key: String, l1_beacon_rpc: String, @@ -58,6 +59,7 @@ impl Config { interval: read_parse_env("INTERVAL"), overhead_interval: read_parse_env("OVERHEAD_INTERVAL"), l1_rollup_address: Address::from_str(&var("L1_ROLLUP").expect("L1_ROLLUP env"))?, + l1_rollup_deploy_block: read_parse_env("GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK"), l2_oracle_address: Address::from_str( &var("L2_GAS_PRICE_ORACLE").expect("L2_GAS_PRICE_ORACLE env"), )?, @@ -125,6 +127,12 @@ fn check_config(config: &Config) -> Result<(), Box> { if config.txn_per_batch < 10u64 { return Err(anyhow!("Check env config error, TXN_PER_BATCH should be more than 10").into()); } + if config.l1_rollup_deploy_block == 0 { + return Err(anyhow!( + "Check env config error, GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK must be non-zero" + ) + .into()); + } Ok(()) } @@ -219,6 +227,7 @@ async fn prepare_updater( ext_signer, l1_rollup, config.l1_beacon_rpc.clone(), + config.l1_rollup_deploy_block, config.gas_threshold, config.commit_scalar_buffer, config.blob_scalar_buffer, @@ -252,6 +261,7 @@ fn register_metrics() { REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.commit_scalar.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.blob_scalar.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.txn_per_batch.clone())).unwrap(); + REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.da_sample_exclusions.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.gas_oracle_owner_balance.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.l1_rpc_status.clone())).unwrap(); } diff --git a/gas-oracle/app/src/l1_base_fee.rs b/gas-oracle/app/src/l1_base_fee.rs index 833e018a6..699bd6891 100644 --- a/gas-oracle/app/src/l1_base_fee.rs +++ b/gas-oracle/app/src/l1_base_fee.rs @@ -145,9 +145,8 @@ impl BaseFeeUpdater { let client: Arc, LocalWallet>> = self.l2_oracle.client(); if need_update { // Update calldata basefee and blob baseFee - let call = self - .l2_oracle - .set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee); + let call = + self.l2_oracle.set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee); let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) .await .map_err(|e| { @@ -215,11 +214,11 @@ async fn query_l1_base_fee( return Err(OracleError::L1BaseFeeError(anyhow!(format!( "Failed to query l1_gas_price: {:#?}", e - )))) + )))); } }; - Ok((l1_base_fee, U256::from(latest_blob_fee), gas_price)) + Ok((l1_base_fee, latest_blob_fee, gas_price)) } #[tokio::test] diff --git a/gas-oracle/app/src/lib.rs b/gas-oracle/app/src/lib.rs index 60e6fa0de..385121cbd 100644 --- a/gas-oracle/app/src/lib.rs +++ b/gas-oracle/app/src/lib.rs @@ -5,6 +5,7 @@ mod error; pub mod gas_price_oracle; mod l1_base_fee; mod metrics; +mod rollup_compat; mod da_scalar; mod signer; @@ -38,4 +39,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:#?}", e) }; error_msg -} \ No newline at end of file +} diff --git a/gas-oracle/app/src/metrics.rs b/gas-oracle/app/src/metrics.rs index f6201e4e2..de9d520fa 100644 --- a/gas-oracle/app/src/metrics.rs +++ b/gas-oracle/app/src/metrics.rs @@ -1,5 +1,5 @@ use lazy_static::lazy_static; -use prometheus::{Gauge, IntGauge, Registry}; +use prometheus::{Gauge, IntCounter, IntGauge, Registry}; pub struct OracleServiceMetrics { pub l1_base_fee: Gauge, @@ -10,6 +10,7 @@ pub struct OracleServiceMetrics { pub commit_scalar: IntGauge, pub blob_scalar: Gauge, pub txn_per_batch: Gauge, + pub da_sample_exclusions: IntCounter, pub l1_rpc_status: IntGauge, } @@ -27,6 +28,11 @@ lazy_static! { .expect("metric can be created"), blob_scalar: Gauge::new("blobScalar", "blob scalar").expect("metric can be created"), txn_per_batch: Gauge::new("txnPerBatch", "txn per batch").expect("metric can be created"), + da_sample_exclusions: IntCounter::new( + "daSampleExclusions", + "canonical DA samples excluded because their source was absent, duplicate, or unverifiable", + ) + .expect("metric can be created"), gas_oracle_owner_balance: Gauge::new("gasOracleOwnerBalance", "gas oracle owner balance") .expect("metric can be created"), l1_rpc_status: IntGauge::new("l1RpcStatus", "l1 prc").expect("metric can be created"), diff --git a/gas-oracle/app/src/rollup_compat.rs b/gas-oracle/app/src/rollup_compat.rs new file mode 100644 index 000000000..b31a5f89c --- /dev/null +++ b/gas-oracle/app/src/rollup_compat.rs @@ -0,0 +1,299 @@ +use ethers::{ + abi::AbiDecode, + contract::EthCall, + providers::Middleware, + types::{Address, BlockId, BlockNumber, Filter, Log, TxHash, H256, U256, U64}, + utils::keccak256, +}; +use eyre::{eyre, Result}; + +use crate::abi::{ + pre_submitter_rollup_abi::{ + CommitBatchCall as PreSubmitterCommitBatchCall, + CommitBatchWithProofCall as PreSubmitterCommitBatchWithProofCall, + CommitStateCall as PreSubmitterCommitStateCall, + }, + rollup_abi::{CommitBatchCall, CommitBatchWithProofCall, CommitStateCall, Rollup}, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[allow(clippy::enum_variant_names)] +pub enum SubmissionKind { + CommitBatch, + CommitState, + CommitBatchWithProof, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BatchDataInput { + pub version: u8, + pub last_block_number: u64, + pub kind: SubmissionKind, + pub pre_submitter: bool, +} + +macro_rules! decoded { + ($input:expr, $kind:expr, $pre:expr) => {{ + let input = $input; + BatchDataInput { + version: input.version, + last_block_number: input.last_block_number, + kind: $kind, + pre_submitter: $pre, + } + }}; +} + +/// Decode only the batch fields consumed by the oracle. The selector is +/// matched before ABI decoding so malformed or unknown calldata fails closed. +pub fn decode_batch_data_input(data: &[u8]) -> Result { + let selector = + data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; + + if selector == CommitBatchCall::selector() { + let call = CommitBatchCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, false)); + } + if selector == CommitStateCall::selector() { + let call = CommitStateCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, false)); + } + if selector == CommitBatchWithProofCall::selector() { + let call = CommitBatchWithProofCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, false)); + } + if selector == PreSubmitterCommitBatchCall::selector() { + let call = PreSubmitterCommitBatchCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, true)); + } + if selector == PreSubmitterCommitStateCall::selector() { + let call = PreSubmitterCommitStateCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, true)); + } + if selector == PreSubmitterCommitBatchWithProofCall::selector() { + let call = PreSubmitterCommitBatchWithProofCall::decode(data)?; + return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, true)); + } + + Err(eyre!("unsupported rollup submission selector")) +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct LogIdentity { + pub block_number: u64, + pub transaction_index: u64, + pub log_index: u64, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CanonicalCommit { + pub identity: LogIdentity, + pub transaction_hash: TxHash, + pub block_hash: H256, + pub batch_hash: H256, +} + +fn identity(log: &Log) -> Option { + Some(LogIdentity { + block_number: log.block_number?.as_u64(), + transaction_index: log.transaction_index?.as_u64(), + log_index: log.log_index?.as_u64(), + }) +} + +/// Select the last same-batch Commit after the last Revert. Full log identity +/// deliberately distinguishes a same-hash recommit from the reverted event. +pub fn select_canonical_commit( + commits: &[Log], + reverts: &[Log], + canonical_hash: H256, +) -> Option { + if canonical_hash.is_zero() { + return None; + } + let last_revert = + reverts.iter().filter(|log| !log.removed.unwrap_or_default()).filter_map(identity).max(); + + commits + .iter() + .filter(|log| !log.removed.unwrap_or_default()) + .filter_map(|log| { + let identity = identity(log)?; + if last_revert.is_some_and(|revert| identity <= revert) { + return None; + } + if log.topics.len() < 3 || log.topics[2] != canonical_hash { + return None; + } + Some(CanonicalCommit { + identity, + transaction_hash: log.transaction_hash?, + block_hash: log.block_hash?, + batch_hash: log.topics[2], + }) + }) + .max_by_key(|commit| commit.identity) +} + +pub const LOG_QUERY_RANGE: u64 = 10_000; + +pub async fn query_batch_logs( + provider: &M, + rollup: Address, + batch_index: u64, + event_topic: H256, + from_block: u64, + to_block: u64, +) -> Result> { + if from_block > to_block { + return Ok(Vec::new()); + } + let mut logs = Vec::new(); + let mut from = from_block; + loop { + let to = from.saturating_add(LOG_QUERY_RANGE - 1).min(to_block); + let filter = Filter::new() + .address(rollup) + .from_block(from) + .to_block(to) + .topic0(event_topic) + .topic1(U256::from(batch_index)); + logs.extend(provider.get_logs(&filter).await.map_err(|err| eyre!(err.to_string()))?); + if to == to_block { + break; + } + from = to + 1; + } + Ok(logs) +} + +pub async fn resolve_canonical_commit( + rollup: &Rollup, + provider: &M, + batch_index: u64, + from_block: u64, + snapshot_number: U64, +) -> Result> { + let before = provider + .get_block(snapshot_number) + .await + .map_err(|err| eyre!(err.to_string()))? + .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; + let before_hash = before.hash.ok_or_else(|| eyre!("snapshot block has no hash"))?; + let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); + let canonical_hash: H256 = rollup + .committed_batches(U256::from(batch_index)) + .block(block_id) + .call() + .await + .map_err(|err| eyre!(err.to_string()))? + .into(); + if canonical_hash.is_zero() { + return Ok(None); + } + + let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); + let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); + let commits = query_batch_logs( + provider, + rollup.address(), + batch_index, + commit_topic, + from_block, + snapshot_number.as_u64(), + ) + .await?; + let reverts = query_batch_logs( + provider, + rollup.address(), + batch_index, + revert_topic, + from_block, + snapshot_number.as_u64(), + ) + .await?; + + let after = provider + .get_block(snapshot_number) + .await + .map_err(|err| eyre!(err.to_string()))? + .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; + if after.hash != Some(before_hash) { + return Err(eyre!("snapshot block hash changed during canonical resolution")); + } + + Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn log(block: u64, marker: u64, hash: H256) -> Log { + Log { + block_number: Some(block.into()), + transaction_index: Some(0.into()), + log_index: Some(0.into()), + transaction_hash: Some(H256::from_low_u64_be(marker)), + block_hash: Some(H256::from_low_u64_be(block)), + topics: vec![H256::zero(), H256::from_low_u64_be(7), hash], + ..Default::default() + } + } + + #[test] + fn rejects_short_and_unknown_calldata() { + assert!(decode_batch_data_input(&[]).is_err()); + assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + } + + #[test] + fn decodes_shared_pre_and_post_submitter_fixtures() { + let corpus: serde_json::Value = serde_json::from_str(include_str!( + "../../../node/derivation/testdata/rollup_calldata_fixtures.json" + )) + .unwrap(); + let mut decoded_count = 0; + for fixture in corpus["fixtures"].as_array().unwrap() { + let epoch = fixture["epoch"].as_str().unwrap(); + if epoch != "pre-submitter" && epoch != "current" { + continue; + } + let data = ethers::utils::hex::decode( + fixture["data"].as_str().unwrap().trim_start_matches("0x"), + ) + .unwrap(); + let decoded = decode_batch_data_input(&data) + .unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); + assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); + assert_eq!( + decoded.last_block_number, + fixture["expected"]["lastBlockNumber"].as_u64().unwrap() + ); + decoded_count += 1; + } + assert_eq!(decoded_count, 6); + } + + #[test] + fn selector_sets_are_frozen() { + assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); + assert_eq!(CommitStateCall::selector(), [0x67, 0xca, 0xa3, 0x7a]); + assert_eq!(CommitBatchWithProofCall::selector(), [0x15, 0x44, 0xba, 0x3a]); + assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); + assert_eq!(PreSubmitterCommitStateCall::selector(), [0x1e, 0x88, 0x25, 0xbe]); + assert_eq!(PreSubmitterCommitBatchWithProofCall::selector(), [0x4e, 0x8f, 0x1d, 0x67]); + } + + #[test] + fn same_hash_recommit_after_revert_wins() { + let hash = H256::from_low_u64_be(99); + let resolved = select_canonical_commit( + &[log(10, 1, hash), log(12, 3, hash)], + &[log(11, 2, hash)], + hash, + ) + .unwrap(); + assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); + } +} diff --git a/gas-oracle/app/src/signer.rs b/gas-oracle/app/src/signer.rs index 7eb865a34..34db74586 100644 --- a/gas-oracle/app/src/signer.rs +++ b/gas-oracle/app/src/signer.rs @@ -122,8 +122,6 @@ fn eip1559_estimator(base_fee_per_gas: U256, _rewards: Vec>) -> (U256, (max_fee_per_gas, max_priority_fee_per_gas) } - - #[tokio::test] #[ignore] async fn test_estimate_eip1559_fees() { @@ -151,6 +149,7 @@ async fn test_estimate_eip1559_fees() { let tx_typed = tx.as_eip1559_mut().unwrap(); log::info!( "====tx_typed gas data: {:?}, {:?}", - tx_typed.max_fee_per_gas, tx_typed.max_priority_fee_per_gas + tx_typed.max_fee_per_gas, + tx_typed.max_priority_fee_per_gas ); } From 6936e97640be30c504282e3e884d892b5c65cfcf Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:14:41 +0800 Subject: [PATCH 12/38] build(bindings): verify reproducible generated artifacts --- .../bindings/centralization_cleanup_test.go | 237 ++++++++++++++++++ bindings/compile.sh | 35 ++- bindings/gen_bindings.sh | 5 +- contracts/package.json | 3 +- contracts/scripts/clean-generated-abi.js | 16 ++ contracts/scripts/verify-abi-archive.js | 36 +++ 6 files changed, 318 insertions(+), 14 deletions(-) create mode 100644 bindings/bindings/centralization_cleanup_test.go create mode 100644 contracts/scripts/clean-generated-abi.js create mode 100644 contracts/scripts/verify-abi-archive.js diff --git a/bindings/bindings/centralization_cleanup_test.go b/bindings/bindings/centralization_cleanup_test.go new file mode 100644 index 000000000..1650aef50 --- /dev/null +++ b/bindings/bindings/centralization_cleanup_test.go @@ -0,0 +1,237 @@ +package bindings + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/morph-l2/go-ethereum/accounts/abi" +) + +const ( + oldCommitBatchSelector = "428868b5" + oldCommitStateSelector = "1e8825be" + oldCommitBatchWithProofSelector = "4e8f1d67" + newCommitBatchSelector = "41f756da" + newCommitStateSelector = "67caa37a" + newCommitBatchWithProofSelector = "1544ba3a" +) + +type calldataCorpus struct { + SchemaVersion int `json:"schemaVersion"` + Fixtures []struct { + Name string `json:"name"` + Epoch string `json:"epoch"` + Selector string `json:"selector"` + Data string `json:"data"` + } `json:"fixtures"` +} + +func repositoryRoot(t *testing.T) string { + t.Helper() + _, filename, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("resolve test source path") + } + return filepath.Clean(filepath.Join(filepath.Dir(filename), "..", "..")) +} + +func readABI(t *testing.T, path string) abi.ABI { + t.Helper() + raw, err := os.Open(path) + if err != nil { + t.Fatalf("open ABI %s: %v", path, err) + } + defer raw.Close() + parsed, err := abi.JSON(raw) + if err != nil { + t.Fatalf("parse ABI %s: %v", path, err) + } + return parsed +} + +func methodSelector(t *testing.T, parsed abi.ABI, name string) string { + t.Helper() + method, ok := parsed.Methods[name] + if !ok { + t.Fatalf("ABI is missing method %s", name) + } + return hex.EncodeToString(method.ID) +} + +func TestGeneratedRollupBindingShape(t *testing.T) { + current, err := RollupMetaData.GetAbi() + if err != nil { + t.Fatalf("parse generated Rollup ABI: %v", err) + } + if current == nil { + t.Fatal("generated Rollup ABI is nil") + } + if strings.Contains(RollupMetaData.ABI, "BatchSignatureInput") { + t.Fatal("generated Rollup binding still contains BatchSignatureInput") + } + + expected := map[string]struct { + selector string + inputs int + }{ + "commitBatch": {newCommitBatchSelector, 1}, + "commitState": {newCommitStateSelector, 1}, + "commitBatchWithProof": {newCommitBatchWithProofSelector, 3}, + } + for name, want := range expected { + method, ok := current.Methods[name] + if !ok { + t.Fatalf("generated Rollup ABI is missing %s", name) + } + if got := hex.EncodeToString(method.ID); got != want.selector { + t.Fatalf("%s selector = %s, want %s", name, got, want.selector) + } + if got := len(method.Inputs); got != want.inputs { + t.Fatalf("%s input count = %d, want %d", name, got, want.inputs) + } + } + + batchDataStore, ok := current.Methods["batchDataStore"] + if !ok { + t.Fatal("generated Rollup ABI is missing batchDataStore") + } + if len(batchDataStore.Outputs) != 4 || batchDataStore.Outputs[3].Type.String() != "address" { + t.Fatalf("batchDataStore output shape = %v, want fourth output address", batchDataStore.Outputs) + } + if _, ok := current.Methods["pendingBatchCount"]; !ok { + t.Fatal("generated Rollup ABI is missing pendingBatchCount") + } +} + +func TestGeneratedSubmitterBindingShape(t *testing.T) { + current, err := SubmitterMetaData.GetAbi() + if err != nil { + t.Fatalf("parse generated Submitter ABI: %v", err) + } + if current == nil { + t.Fatal("generated Submitter ABI is nil") + } + for _, name := range []string{ + "addSubmitter", + "claimCredit", + "claimWithdrawal", + "initialize", + "isActive", + "removeSubmitter", + "slash", + "stake", + "withdraw", + } { + if _, ok := current.Methods[name]; !ok { + t.Fatalf("generated Submitter ABI is missing %s", name) + } + } + active := current.Methods["isActive"] + if len(active.Inputs) != 1 || len(active.Outputs) != 1 || active.Outputs[0].Type.String() != "bool" { + t.Fatalf("isActive ABI shape changed: inputs=%v outputs=%v", active.Inputs, active.Outputs) + } +} + +func TestPreSubmitterAndCurrentSelectorsRemainDistinct(t *testing.T) { + root := repositoryRoot(t) + preSubmitter := readABI(t, filepath.Join( + root, + "contracts", + "abi", + "archive", + "pre-submitter", + "Rollup.json", + )) + current, err := RollupMetaData.GetAbi() + if err != nil || current == nil { + t.Fatalf("parse generated Rollup ABI: %v", err) + } + + tests := []struct { + name string + oldSelector string + newSelector string + oldInputCount int + newInputCount int + }{ + {"commitBatch", oldCommitBatchSelector, newCommitBatchSelector, 2, 1}, + {"commitState", oldCommitStateSelector, newCommitStateSelector, 2, 1}, + {"commitBatchWithProof", oldCommitBatchWithProofSelector, newCommitBatchWithProofSelector, 4, 3}, + } + for _, test := range tests { + oldMethod := preSubmitter.Methods[test.name] + newMethod := current.Methods[test.name] + if got := methodSelector(t, preSubmitter, test.name); got != test.oldSelector { + t.Fatalf("pre-submitter %s selector = %s, want %s", test.name, got, test.oldSelector) + } + if got := methodSelector(t, *current, test.name); got != test.newSelector { + t.Fatalf("current %s selector = %s, want %s", test.name, got, test.newSelector) + } + if bytes.Equal(oldMethod.ID, newMethod.ID) { + t.Fatalf("pre-submitter and current %s selectors collide", test.name) + } + if len(oldMethod.Inputs) != test.oldInputCount || len(newMethod.Inputs) != test.newInputCount { + t.Fatalf( + "%s input counts = old %d/current %d, want old %d/current %d", + test.name, + len(oldMethod.Inputs), + len(newMethod.Inputs), + test.oldInputCount, + test.newInputCount, + ) + } + } +} + +func TestSupportedRollupSelectorsHaveNoCollisions(t *testing.T) { + root := repositoryRoot(t) + raw, err := os.ReadFile(filepath.Join( + root, + "node", + "derivation", + "testdata", + "rollup_calldata_fixtures.json", + )) + if err != nil { + t.Fatalf("read shared calldata corpus: %v", err) + } + var corpus calldataCorpus + if err := json.Unmarshal(raw, &corpus); err != nil { + t.Fatalf("parse shared calldata corpus: %v", err) + } + if corpus.SchemaVersion != 1 || len(corpus.Fixtures) != 8 { + t.Fatalf("shared calldata corpus shape = version %d/%d fixtures, want version 1/8 fixtures", corpus.SchemaVersion, len(corpus.Fixtures)) + } + + seen := make(map[string]string, len(corpus.Fixtures)) + for _, fixture := range corpus.Fixtures { + selector := strings.TrimPrefix(strings.ToLower(fixture.Selector), "0x") + data := strings.TrimPrefix(strings.ToLower(fixture.Data), "0x") + if len(selector) != 8 || len(data) < 8 || data[:8] != selector { + t.Fatalf("fixture %s has inconsistent selector/data", fixture.Name) + } + if previous, ok := seen[selector]; ok { + t.Fatalf("selector collision %s between %s and %s", selector, previous, fixture.Name) + } + seen[selector] = fixture.Name + } + + for _, selector := range []string{ + oldCommitBatchSelector, + oldCommitStateSelector, + oldCommitBatchWithProofSelector, + newCommitBatchSelector, + newCommitStateSelector, + newCommitBatchWithProofSelector, + } { + if _, ok := seen[selector]; !ok { + t.Fatalf("shared calldata corpus is missing protected selector %s", selector) + } + } +} diff --git a/bindings/compile.sh b/bindings/compile.sh index 936cec851..920a29368 100755 --- a/bindings/compile.sh +++ b/bindings/compile.sh @@ -1,4 +1,6 @@ -#/bin/bash +#!/usr/bin/env bash + +set -euo pipefail CONTRACTS_PATH="../contracts/" cd $CONTRACTS_PATH || exit @@ -13,33 +15,44 @@ forge_compile() { CONTRACTS_PATH="../contracts/" cd $CONTRACTS_PATH || exit yarn clean - sed -i '.bak' '10a\ -import "@foundry-rs/hardhat-forge";' hardhat.config.ts + + config_backup=$(mktemp) + foundry_backup=$(mktemp) + cp hardhat.config.ts "$config_backup" + cp foundry.toml "$foundry_backup" + restore_sources() { + cp "$config_backup" hardhat.config.ts + cp "$foundry_backup" foundry.toml + rm -f "$config_backup" "$foundry_backup" + } + trap restore_sources EXIT + + { + echo 'import "@foundry-rs/hardhat-forge";' + cat "$config_backup" + } > hardhat.config.ts yarn directory=$(pwd)"/contracts" # shellcheck disable=SC2034 main_dirname=$(basename "$directory") - backup_extension=".bak" - find "$directory" -mindepth 1 -maxdepth 1 -type d | while read dir; do dirname=$(basename "$dir") # shellcheck disable=SC2116 subdirs=$(echo "'contracts/$dirname'") echo "$subdirs" - sed -i "$backup_extension" "2s|.*|src = $subdirs|" foundry.toml + awk -v source="$subdirs" 'NR == 2 { $0 = "src = " source } { print }' \ + "$foundry_backup" > foundry.toml yarn hardhat compile done - sed -i "$backup_extension" "2s|.*|src = 'contracts'|" foundry.toml - sed -i "$backup_extension" '11s/.*//' hardhat.config.ts - rm -rf foundry.toml.bak - rm -rf hardhat.config.ts.bak + restore_sources + trap - EXIT } #!/bin/bash -if [ ! -n "$1" ]; then +if [ "$#" -eq 0 ]; then echo "hardhat compile" hardhat_compile else diff --git a/bindings/gen_bindings.sh b/bindings/gen_bindings.sh index 619f944f8..886d19d80 100755 --- a/bindings/gen_bindings.sh +++ b/bindings/gen_bindings.sh @@ -1,4 +1,4 @@ -#/bin/bash +#!/usr/bin/env bash set -eu CONTRACTS_PATH="../contracts/" @@ -54,4 +54,5 @@ abigen \ # Place import "github.com/ethereum/go-ethereum" to "github.com/morph-l2/go-ethereum" TO_REPLACED_STRING="github.com/ethereum/go-ethereum" NEW_STRING="github.com/morph-l2/go-ethereum" -sed -i "" -e "s#${TO_REPLACED_STRING}#${NEW_STRING}#g" ./${PACKAGE}/${TYPE_LOWER}.go +sed -i.bak -e "s#${TO_REPLACED_STRING}#${NEW_STRING}#g" ./${PACKAGE}/${TYPE_LOWER}.go +rm -f ./${PACKAGE}/${TYPE_LOWER}.go.bak diff --git a/contracts/package.json b/contracts/package.json index 810c56de1..7bf7d938c 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -23,9 +23,10 @@ "test": "yarn test:hardhat && yarn test:forge", "clean": "yarn clean:build && yarn clean:compile && yarn clean:tsc", "clean:build": "rm -rf ./dist ./cache ./cache-hardhat ./node_modules ./logs", - "clean:compile": "rm -rf ./idea ./forge_artifacts ./abi ./artifacts ./typechain-types ./forge-artifacts", + "clean:compile": "rm -rf ./idea ./forge_artifacts ./artifacts ./typechain-types ./forge-artifacts && node scripts/clean-generated-abi.js", "clean:tsc": "rm -rf ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts", "typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'", + "verify:abi-archive": "node scripts/verify-abi-archive.js", "deploy:devnetL1": "rm -f devnetL1.json && hardhat deploy --network l1 --storagepath devnetL1.json", "initialize:devnetL1": "hardhat initialize --network l1 --storagepath devnetL1.json", "register:devnetL1": "hardhat register --network l1 --storagepath devnetL1.json", diff --git a/contracts/scripts/clean-generated-abi.js b/contracts/scripts/clean-generated-abi.js new file mode 100644 index 000000000..c43402d14 --- /dev/null +++ b/contracts/scripts/clean-generated-abi.js @@ -0,0 +1,16 @@ +const fs = require('fs') +const path = require('path') + +const { archiveDir, verifyAbiArchive } = require('./verify-abi-archive') + +verifyAbiArchive() + +const abiDir = path.dirname(archiveDir) +for (const entry of fs.readdirSync(abiDir, { withFileTypes: true })) { + if (entry.name === path.basename(archiveDir)) { + continue + } + fs.rmSync(path.join(abiDir, entry.name), { recursive: true, force: true }) +} + +verifyAbiArchive() diff --git a/contracts/scripts/verify-abi-archive.js b/contracts/scripts/verify-abi-archive.js new file mode 100644 index 000000000..db6527658 --- /dev/null +++ b/contracts/scripts/verify-abi-archive.js @@ -0,0 +1,36 @@ +const crypto = require('crypto') +const fs = require('fs') +const path = require('path') + +const archiveDir = path.resolve(__dirname, '..', 'abi', 'archive') +const manifestPath = path.join(archiveDir, 'manifest.json') + +function verifyAbiArchive() { + if (!fs.existsSync(manifestPath)) { + throw new Error(`frozen ABI manifest is missing: ${manifestPath}`) + } + + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) + for (const [relativePath, expectedHash] of Object.entries(manifest.artifacts)) { + const artifactPath = path.resolve(archiveDir, relativePath) + if (!fs.existsSync(artifactPath)) { + throw new Error(`frozen ABI artifact is missing: ${artifactPath}`) + } + const actualHash = crypto + .createHash('sha256') + .update(fs.readFileSync(artifactPath)) + .digest('hex') + if (actualHash !== expectedHash) { + throw new Error( + `frozen ABI hash mismatch for ${relativePath}: expected ${expectedHash}, got ${actualHash}` + ) + } + } +} + +if (require.main === module) { + verifyAbiArchive() + console.log('Frozen ABI archive hashes verified') +} + +module.exports = { archiveDir, verifyAbiArchive } From e3106ce87ed5a9c0a3c33677c9ed8a9f9c504c1b Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:16:51 +0800 Subject: [PATCH 13/38] build(gas-oracle): pin native KZG toolchain --- ops/docker/Dockerfile.oracle | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ops/docker/Dockerfile.oracle b/ops/docker/Dockerfile.oracle index b25c1fdac..c0e2a5a3d 100644 --- a/ops/docker/Dockerfile.oracle +++ b/ops/docker/Dockerfile.oracle @@ -1,7 +1,7 @@ -FROM rust:1.88-slim as builder +FROM rust:1.91.0-slim as builder RUN apt-get -qq update && apt-get -qq install -y --no-install-recommends \ - pkg-config libssl-dev && rm -rf /var/lib/apt/lists/* + build-essential pkg-config libssl-dev && rm -rf /var/lib/apt/lists/* COPY ./gas-oracle /gas-oracle @@ -9,6 +9,8 @@ WORKDIR /gas-oracle RUN cd app && cargo build --release FROM ubuntu:22.04 as app +RUN apt-get -qq update && apt-get -qq install -y --no-install-recommends \ + ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /gas-oracle/app/target/release/app / -CMD ["./app"] \ No newline at end of file +CMD ["./app"] From 93e512b856cec95acd0da23c4743bbd1f2c3bf80 Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:24:12 +0800 Subject: [PATCH 14/38] fix(node): retain audited legacy validator path --- node/core/sequencers.go | 6 ++++++ node/derivation/canonical_commit.go | 2 +- node/go.mod | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/node/core/sequencers.go b/node/core/sequencers.go index c19f9335e..0ed154285 100644 --- a/node/core/sequencers.go +++ b/node/core/sequencers.go @@ -12,6 +12,12 @@ import ( const tmKeySize = ed25519.PubKeySize +// Keep the protected pre-cutover update path addressable for symbol-level +// audits even though all production entry points now use validatorSetAtHeight. +// The method bodies below intentionally remain unchanged apart from removing +// the old syncer-start side effect. +var _ = (*Executor).updateSequencerSet + func cloneValidatorKeys(keys [][]byte) [][]byte { cloned := make([][]byte, len(keys)) for i := range keys { diff --git a/node/derivation/canonical_commit.go b/node/derivation/canonical_commit.go index 9d3b6b454..09241d010 100644 --- a/node/derivation/canonical_commit.go +++ b/node/derivation/canonical_commit.go @@ -257,7 +257,7 @@ func ResolveStoredBlobSourceAtSnapshot( if err != nil { return nil, fmt.Errorf("decode stored blob source transaction %s: %w", log.TxHash.Hex(), err) } - if !storedBlobHashMatches(uint(batch.Version), blobHashes, storedHash) { + if !storedBlobHashMatches(batch.Version, blobHashes, storedHash) { continue } source = &StoredBlobSource{ diff --git a/node/go.mod b/node/go.mod index fd46c9d89..2b127d3aa 100644 --- a/node/go.mod +++ b/node/go.mod @@ -12,6 +12,7 @@ require ( github.com/hashicorp/golang-lru v1.0.2 github.com/hashicorp/raft v1.7.3 github.com/hashicorp/raft-boltdb/v2 v2.3.1 + github.com/holiman/uint256 v1.2.4 github.com/mdlayher/vsock v1.2.1 github.com/morph-l2/go-ethereum v1.10.14-0.20260810084402-5a13ad4d76fe github.com/pkg/errors v0.9.1 @@ -73,7 +74,6 @@ require ( github.com/hashicorp/go-uuid v1.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iden3/go-iden3-crypto v0.0.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect From 434bb7ed123651f8cd7f5f9b246610393253bd6e Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:26:03 +0800 Subject: [PATCH 15/38] ci: gate centralization cleanup consumers --- .github/workflows/bindings.yml | 60 ++++++++++++++++++++++++++++++ .github/workflows/cherry-pick.yml | 4 +- .github/workflows/common.yml | 37 ++++++++++++++++++ .github/workflows/contracts.yml | 21 +++++++---- .github/workflows/deployer.yml | 9 +++-- .github/workflows/gas-oracle.yml | 22 +++++++++-- .github/workflows/node.yml | 9 +++-- .github/workflows/ops.yml | 52 ++++++++++++++++++++++++++ .github/workflows/prover.yml | 35 +++++++++++++---- .github/workflows/tx-submitter.yml | 12 ++++-- build/lint.go | 2 +- 11 files changed, 230 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/bindings.yml create mode 100644 .github/workflows/common.yml create mode 100644 .github/workflows/ops.yml diff --git a/.github/workflows/bindings.yml b/.github/workflows/bindings.yml new file mode 100644 index 000000000..eb0b09fd2 --- /dev/null +++ b/.github/workflows/bindings.yml @@ -0,0 +1,60 @@ +name: Bindings + +on: + push: + branches: + - main + paths: + - "build/lint.go" + - "bindings/**" + - "contracts/**" + - ".github/workflows/bindings.yml" + pull_request: + paths: + - "build/lint.go" + - "bindings/**" + - "contracts/**" + - ".github/workflows/bindings.yml" + +permissions: + contents: read + +jobs: + generate-and-test: + name: generate and test + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x + - name: Install Node + uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: yarn + cache-dependency-path: contracts/yarn.lock + - name: Install pinned Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly-2024-02-23 + - name: Install pinned abigen + run: | + mkdir -p "$RUNNER_TEMP/bin" + GOBIN="$RUNNER_TEMP/bin" go install github.com/ethereum/go-ethereum/cmd/abigen@v1.14.6 + echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" + - name: Regenerate bindings + run: | + yarn --cwd contracts verify:abi-archive + make -C bindings all + yarn --cwd contracts verify:abi-archive + - name: Verify generated files are committed + run: >- + git diff --exit-code -- + bindings/bindings bindings/bin contracts/abi/archive + - name: Run bindings tests + run: make -C bindings test + - name: Lint bindings + run: make -C bindings lint diff --git a/.github/workflows/cherry-pick.yml b/.github/workflows/cherry-pick.yml index 698d82818..e43bc1161 100644 --- a/.github/workflows/cherry-pick.yml +++ b/.github/workflows/cherry-pick.yml @@ -15,7 +15,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'release/0.1.x') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cherry pick into release/0.1.x @@ -31,7 +31,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'release/0.2.x') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cherry pick into release/0.2.x diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml new file mode 100644 index 000000000..194bf565f --- /dev/null +++ b/.github/workflows/common.yml @@ -0,0 +1,37 @@ +name: Common + +on: + push: + branches: + - main + paths: + - "bindings/**" + - "common/**" + - "node/derivation/testdata/rollup_calldata_fixtures.json" + - ".github/workflows/common.yml" + pull_request: + paths: + - "bindings/**" + - "common/**" + - "node/derivation/testdata/rollup_calldata_fixtures.json" + - ".github/workflows/common.yml" + +permissions: + contents: read + +defaults: + run: + working-directory: "common" + +jobs: + test: + name: race tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x + - name: Run tests with race detector + run: go test -race ./... diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index 8d3a270d4..40c6b0418 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -5,14 +5,15 @@ on: branches: - main paths: + - "build/**" - "contracts/**" - - ".github/workflows/contracts.yaml" + - ".github/workflows/contracts.yml" pull_request: paths: - "build/**" - "contracts/**" - "ops/l2-genesis/**" - - ".github/workflows/contracts.yaml" + - ".github/workflows/contracts.yml" permissions: contents: read @@ -26,15 +27,21 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18.x + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x - name: Install Solhint run: npm install -g solhint - - name: Lint + - name: Lint Solidity run: make lint-sol + - name: Lint Go + run: make lint-go test: runs-on: ubuntu-latest @@ -42,9 +49,9 @@ jobs: FORCE_COLOR: 1 GAS: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18.x - name: Install Go diff --git a/.github/workflows/deployer.yml b/.github/workflows/deployer.yml index 184680c6b..50e976db4 100644 --- a/.github/workflows/deployer.yml +++ b/.github/workflows/deployer.yml @@ -5,15 +5,16 @@ on: branches: - main paths: + - "build/**" - "ops/l2-genesis/**" - - ".github/workflows/deployer.yaml" + - ".github/workflows/deployer.yml" pull_request: paths: - "build/**" - "bindings/**" - "node/**" - "ops/l2-genesis/**" - - ".github/workflows/deployer.yaml" + - ".github/workflows/deployer.yml" permissions: contents: read @@ -27,7 +28,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: @@ -39,7 +40,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/.github/workflows/gas-oracle.yml b/.github/workflows/gas-oracle.yml index ab1e3ea80..51149f7aa 100644 --- a/.github/workflows/gas-oracle.yml +++ b/.github/workflows/gas-oracle.yml @@ -6,11 +6,15 @@ on: - main paths: - "gas-oracle/**" - - ".github/workflows/gas-oracle.yaml" + - "node/derivation/testdata/rollup_calldata_fixtures.json" + - "ops/docker/Dockerfile.oracle" + - ".github/workflows/gas-oracle.yml" pull_request: paths: - "gas-oracle/**" - - ".github/workflows/gas-oracle.yaml" + - "node/derivation/testdata/rollup_calldata_fixtures.json" + - "ops/docker/Dockerfile.oracle" + - ".github/workflows/gas-oracle.yml" permissions: contents: read @@ -23,8 +27,20 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Install pinned Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.91.0 + components: rustfmt, clippy - name: Run build run: make build - name: Run tests run: make test + - name: Check formatting + run: make fmt + - name: Run clippy + run: make clippy + - name: Build oracle container + working-directory: ${{ github.workspace }} + run: docker build -f ops/docker/Dockerfile.oracle . diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 8b9773d3e..559606c94 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -5,15 +5,16 @@ on: branches: - main paths: + - "build/**" - "node/**" - - ".github/workflows/node.yaml" + - ".github/workflows/node.yml" pull_request: paths: - "build/**" - "bindings/**" - "node/**" - "ops/l2-genesis/**" - - ".github/workflows/node.yaml" + - ".github/workflows/node.yml" permissions: contents: read @@ -27,7 +28,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: @@ -39,7 +40,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/.github/workflows/ops.yml b/.github/workflows/ops.yml new file mode 100644 index 000000000..00037a109 --- /dev/null +++ b/.github/workflows/ops.yml @@ -0,0 +1,52 @@ +name: Ops + +on: + push: + branches: + - main + paths: + - "build/**" + - "node/ops-morph/**" + - "ops/devnet-morph/**" + - "ops/docker/**" + - "ops/tools/**" + - ".github/workflows/ops.yml" + pull_request: + paths: + - "build/**" + - "node/ops-morph/**" + - "ops/devnet-morph/**" + - "ops/docker/**" + - "ops/tools/**" + - ".github/workflows/ops.yml" + +permissions: + contents: read + +jobs: + go-lint: + name: ops tools lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x + - name: Lint ops tools + run: make -C ops/tools lint + + devnet-config: + name: devnet config tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run deterministic devnet tests + run: python3 -m unittest discover -s ops/devnet-morph/tests -v + - name: Validate Compose configuration + working-directory: ops/docker + run: >- + docker compose + -f docker-compose-devnet.yml + -f docker-compose-cluster.yml + config --quiet diff --git a/.github/workflows/prover.yml b/.github/workflows/prover.yml index 8e611539a..bdc222c9f 100644 --- a/.github/workflows/prover.yml +++ b/.github/workflows/prover.yml @@ -5,12 +5,14 @@ on: branches: - main paths: + - "node/derivation/testdata/rollup_calldata_fixtures.json" - "prover/**" - - ".github/workflows/prover.yaml" + - ".github/workflows/prover.yml" pull_request: paths: + - "node/derivation/testdata/rollup_calldata_fixtures.json" - "prover/**" - - ".github/workflows/prover.yaml" + - ".github/workflows/prover.yml" permissions: contents: read @@ -26,15 +28,32 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: rustup component add rustfmt --toolchain nightly-2024-07-07 - - run: cargo fmt --all --check + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2024-07-07 + components: rustfmt + - name: Check shadow-prove formatting + run: cargo +nightly-2024-07-07 fmt --package shadow-proving --check + - name: Check challenge formatting + run: >- + cargo +nightly-2024-07-07 fmt + --manifest-path bin/challenge/Cargo.toml + --check build: name: build runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 60 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: make build-shadow-prove && make build-shadow-prove + - uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.91.0 + - name: Build shadow-prove + run: make build-shadow-prove + - name: Test shadow-prove + run: cargo test --manifest-path bin/shadow-prove/Cargo.toml + - name: Build challenge + run: make build-challenge + - name: Test challenge + run: cargo test --manifest-path bin/challenge/Cargo.toml diff --git a/.github/workflows/tx-submitter.yml b/.github/workflows/tx-submitter.yml index ae8fec5b3..171e9b56b 100644 --- a/.github/workflows/tx-submitter.yml +++ b/.github/workflows/tx-submitter.yml @@ -5,16 +5,20 @@ on: branches: - main paths: + - "build/**" + - "bindings/**" + - "common/**" - "tx-submitter/**" - - ".github/workflows/tx-submitter.yaml" + - ".github/workflows/tx-submitter.yml" pull_request: paths: - "build/**" - "bindings/**" + - "common/**" - "node/**" - "ops/l2-genesis/**" - "tx-submitter/**" - - ".github/workflows/tx-submitter.yaml" + - ".github/workflows/tx-submitter.yml" permissions: contents: read @@ -28,7 +32,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: @@ -40,7 +44,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/build/lint.go b/build/lint.go index e12ac1cc0..002a7d1f9 100644 --- a/build/lint.go +++ b/build/lint.go @@ -15,7 +15,7 @@ import ( const ( // GolangCIVersion to be used for linting. - GolangCIVersion = "github.com/golangci/golangci-lint/cmd/golangci-lint@latest" + GolangCIVersion = "github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8" ) // GOBIN environment variable. From 2550618f1267f2c4577eeb176d463fa739f6d9fe Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 21:29:37 +0800 Subject: [PATCH 16/38] fix(prover): cache canonical logs and fail over signers --- prover/bin/challenge/.env.dev | 4 + .../bin/challenge/src/bin/auto_challenge.rs | 19 +- prover/bin/challenge/src/handler.rs | 168 ++++----- prover/bin/challenge/src/lib.rs | 1 + prover/bin/challenge/src/main.rs | 2 + prover/bin/challenge/src/metrics.rs | 3 + prover/bin/challenge/src/proof_signer.rs | 155 ++++++++ prover/bin/challenge/src/rollup_compat.rs | 290 ++++++++++++--- prover/bin/shadow-prove/src/rollup_compat.rs | 340 ++++++++++++++---- prover/bin/shadow-prove/src/shadow_rollup.rs | 54 ++- 10 files changed, 795 insertions(+), 241 deletions(-) create mode 100644 prover/bin/challenge/src/proof_signer.rs diff --git a/prover/bin/challenge/.env.dev b/prover/bin/challenge/.env.dev index 847cbb13e..e0b5e4a3e 100644 --- a/prover/bin/challenge/.env.dev +++ b/prover/bin/challenge/.env.dev @@ -7,6 +7,10 @@ HANDLER_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" # deployment block from the deployment manifest. HANDLER_L1_ROLLUP_DEPLOY_BLOCK = 1 CHALLENGE_HANDLER_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +# Comma-separated, explicitly approved local failover keys. The primary key is +# always evaluated first and no backup is used unless its address is active at +# the same finalized L1 snapshot. +CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS = "" SHADOW_PROVING = true # challenger diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index 2d41cda37..29aa69c96 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -1,5 +1,5 @@ use challenge_handler::abi::rollup_abi::Rollup; -use challenge_handler::rollup_compat::{challenge_deposit_at, resolve_canonical_commit}; +use challenge_handler::rollup_compat::{challenge_deposit_at, CanonicalLogIndex}; use challenge_handler::util::read_parse_env; use dotenv::dotenv; use env_logger::Env; @@ -69,13 +69,20 @@ pub async fn challenge() -> Result<(), Box> { let proof_window = l1_rollup.proof_window().await?; log::info!("finalization_period: {:#?} proof_window: {:#?}", finalization_period, proof_window); + let mut canonical_log_index = CanonicalLogIndex::new(rollup_deployed_block)?; loop { tokio::time::sleep(Duration::from_secs(12)).await; - let _ = auto_challenge(&l1_provider, &l1_rollup, rollup_deployed_block).await; + if let Err(error) = auto_challenge(&l1_provider, &l1_rollup, &mut canonical_log_index).await { + log::error!("ALERT: auto-challenge iteration failed closed: {error:#}"); + } } } -async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, rollup_deployed_block: u64) -> Result<(), Box> { +async fn auto_challenge( + l1_provider: &Provider, + l1_rollup: &RollupType, + canonical_log_index: &mut CanonicalLogIndex, +) -> Result<(), Box> { // Search for the latest batch. let (latest, snapshot_hash) = match l1_provider.get_block(BlockNumber::Finalized).await { Ok(Some(block)) => match (block.number, block.hash) { @@ -114,7 +121,11 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, ro let block_id = BlockId::Number(BlockNumber::Number(latest)); let min_deposit = challenge_deposit_at(l1_rollup, block_id).await?; let batch_index = l1_rollup.last_committed_batch_index().block(block_id).call().await?.as_u64(); - if resolve_canonical_commit(l1_rollup, l1_provider, batch_index, rollup_deployed_block, latest) + canonical_log_index + .refresh(l1_provider, l1_rollup.address(), latest, snapshot_hash) + .await?; + if canonical_log_index + .resolve(l1_rollup, batch_index, latest, snapshot_hash) .await? .is_none() { diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 572d17a7a..68e199dd9 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,9 +1,8 @@ use crate::abi::rollup_abi::Rollup; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; -use crate::rollup_compat::{ - authority_is_active, decode_batch_data_input, decode_batch_data_store_block_number, resolve_canonical_commit, CanonicalCommit, -}; +use crate::proof_signer::{select_active_proof_signer, ApprovedProofSigner}; +use crate::rollup_compat::{decode_batch_data_input, decode_batch_data_store_block_number, CanonicalCommit, CanonicalLogIndex}; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; use ethers::prelude::*; @@ -18,6 +17,7 @@ use std::error::Error; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; +use tokio::sync::Mutex; use tokio::time::sleep; use transaction::eip2718::TypedTransaction; @@ -53,8 +53,8 @@ pub struct ChallengeHandler { l1_rollup: RollupType, l1_provider: Provider, l2_rpc: String, - ext_signer: Option, - rollup_deployed_block: u64, + proof_signers: Vec, + canonical_log_index: Arc>, } impl ChallengeHandler { @@ -65,6 +65,9 @@ impl ChallengeHandler { let l1_rollup_address = var("HANDLER_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let _ = var("HANDLER_PROVER_RPC").expect("Cannot detect PROVER_RPC env var"); let rollup_deployed_block: u64 = read_parse_env("HANDLER_L1_ROLLUP_DEPLOY_BLOCK"); + let canonical_log_index = Arc::new(Mutex::new( + CanonicalLogIndex::new(rollup_deployed_block).expect("HANDLER_L1_ROLLUP_DEPLOY_BLOCK must be non-zero"), + )); let private_key = read_env_var( "CHALLENGE_HANDLER_PRIVATE_KEY", @@ -72,17 +75,14 @@ impl ChallengeHandler { ); let l1_provider: Provider = Provider::::try_from(l1_rpc).unwrap(); - let l1_signer = Arc::new(SignerMiddleware::new( - l1_provider.clone(), - Wallet::from_str(private_key.as_str()) - .unwrap() - .with_chain_id(l1_provider.get_chainid().await.unwrap().as_u64()), - )); + let chain_id = l1_provider.get_chainid().await.unwrap().as_u64(); + let local_wallet = Wallet::from_str(private_key.as_str()).unwrap().with_chain_id(chain_id); + let l1_signer = Arc::new(SignerMiddleware::new(l1_provider.clone(), local_wallet.clone())); let l1_rollup: RollupType = Rollup::new(Address::from_str(l1_rollup_address.as_str()).unwrap(), l1_signer); let use_ext_sign: bool = read_env_var("HANDLER_EXTERNAL_SIGN", false); - let ext_signer = if use_ext_sign { + let primary_signer = if use_ext_sign { log::info!("Challenge handler will use external signer"); let handler_appid: String = read_parse_env("HANDLER_EXTERNAL_SIGN_APPID"); let privkey_pem: String = read_parse_env("HANDLER_EXTERNAL_SIGN_RSA_PRIV"); @@ -92,18 +92,32 @@ impl ChallengeHandler { let signer: ExternalSign = ExternalSign::new(&handler_appid, &privkey_pem, &sign_address, &sign_chain, &sign_url) .map_err(|e| anyhow!(format!("Prepare ExternalSign err: {:?}", e))) .unwrap(); - Some(signer) + let address = Address::from_str(&signer.address).expect("HANDLER_EXTERNAL_SIGN_ADDRESS must be a valid address"); + ApprovedProofSigner::external(address, signer) } else { log::info!("Challenge handler will use local signer"); - None + ApprovedProofSigner::local(local_wallet) }; + let mut proof_signers = vec![primary_signer]; + let backup_private_keys: String = read_env_var("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS", String::new()); + for backup_private_key in backup_private_keys.split(',').map(str::trim).filter(|key| !key.is_empty()) { + let wallet = Wallet::from_str(backup_private_key) + .expect("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS contains an invalid private key") + .with_chain_id(chain_id); + if proof_signers.iter().any(|approved| approved.address() == wallet.address()) { + panic!("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS contains a duplicate approved signer"); + } + proof_signers.push(ApprovedProofSigner::local(wallet)); + } + log::info!("Configured {} ordered approved proof signer(s)", proof_signers.len()); + Self { l1_rollup, l1_provider, l2_rpc, - ext_signer, - rollup_deployed_block, + proof_signers, + canonical_log_index, } } @@ -150,11 +164,7 @@ impl ChallengeHandler { }; log::info!("Current L1 block number: {:#?}", latest); - let wallet = if let Some(signer) = &self.ext_signer { - Address::from_str(&signer.address).unwrap_or_default() - } else { - self.l1_rollup.client().address() - }; + let wallet = self.proof_signers[0].address(); // Record wallet balance. let balance = match l1_provider.get_balance(wallet, None).await { Ok(b) => b, @@ -177,11 +187,11 @@ impl ChallengeHandler { METRICS.detected_batch_index.set(batch_index as i64); // Step3. query challenged batch info. - let (challenged_commit, batch_hash) = match query_batch_tx(latest, l1_rollup, batch_index, self.rollup_deployed_block, l1_provider).await - { - Some(value) => value, - None => continue, - }; + let (challenged_commit, batch_hash) = + match query_batch_tx(latest, snapshot_hash, l1_rollup, batch_index, &self.canonical_log_index, l1_provider).await { + Some(value) => value, + None => continue, + }; let mut batch_info = match batch_inspect(l1_rollup, l1_provider, batch_index, &challenged_commit, latest).await { Some(mut b) => { @@ -277,24 +287,39 @@ impl ChallengeHandler { } async fn prove_state(&self, batch_index: u64, batch_header: Bytes, batch_proof: ProveResult, l1_rollup: &RollupType) -> bool { - let signer = if let Some(external) = &self.ext_signer { - Address::from_str(&external.address).unwrap_or_default() - } else { - l1_rollup.client().address() - }; for _ in 0..MAX_RETRY_TIMES { sleep(Duration::from_secs(12)).await; - if !self.proof_signer_is_active(l1_rollup, signer).await { - // Re-run the gate before every retry: a threshold increase, - // exit, or slash between attempts must stop transmission. - return false; + METRICS.proof_signer_available.set(0); + let selected = match select_active_proof_signer(l1_rollup, &self.proof_signers).await { + Ok(Some(selected)) => selected, + Ok(None) => { + log::error!( + "ALERT: refusing proveState because all {} approved proof signers are inactive; no transaction was sent", + self.proof_signers.len() + ); + return false; + } + Err(err) => { + log::error!("ALERT: refusing proveState because active signer selection failed: {err:#}; no transaction was sent"); + return false; + } + }; + METRICS.proof_signer_available.set(1); + if selected.approved_index > 0 { + log::warn!( + "ALERT: primary proof signer is inactive; switching to approved backup #{} {:?} at finalized snapshot {} ({:?})", + selected.approved_index, + selected.signer.address(), + selected.snapshot.number, + selected.snapshot.hash + ); } log::info!("starting prove state onchain, batch index = {:#?}", batch_index); let proof = Bytes::from(batch_proof.proof_data.clone()); let client: Arc, LocalWallet>> = self.l1_rollup.client(); let calldata = l1_rollup.prove_state(batch_header.clone(), proof).calldata(); - let result = send_transaction(self.l1_rollup.address(), calldata, &client, &self.ext_signer, &self.l1_provider).await; + let result = send_transaction(self.l1_rollup.address(), calldata, &client, &selected.signer, &self.l1_provider).await; if let Ok(tx_hash) = result { METRICS.verify_result.set(1); log::info!("prove_state success, batch_index: {:?}, tx_hash: {:#?}", batch_index, tx_hash); @@ -309,42 +334,6 @@ impl ChallengeHandler { } false } - - async fn proof_signer_is_active(&self, l1_rollup: &RollupType, signer: Address) -> bool { - let (number, hash) = match self.l1_provider.get_block(BlockNumber::Finalized).await { - Ok(Some(block)) => match (block.number, block.hash) { - (Some(number), Some(hash)) => (number, hash), - _ => { - log::error!("finalized L1 block has no stable identity"); - return false; - } - }, - Ok(None) => { - log::error!("finalized L1 block is unavailable"); - return false; - } - Err(err) => { - log::error!("query finalized L1 snapshot failed: {err:#}"); - return false; - } - }; - let snapshot = BlockId::Number(BlockNumber::Number(number)); - let active = match authority_is_active(l1_rollup, signer, snapshot).await { - Ok(active) => active, - Err(err) => { - log::error!("Rollup authority active preflight failed: {err:#}"); - return false; - } - }; - if !snapshot_unchanged(&self.l1_provider, number, hash).await { - log::error!("finalized snapshot changed during authority active preflight"); - return false; - } - if !active { - log::error!("refusing proveState from inactive submitter signer {signer:?}"); - } - active - } } /** @@ -376,12 +365,18 @@ async fn query_proof(batch_index: u64) -> Option { async fn query_batch_tx( latest: U64, + snapshot_hash: H256, l1_rollup: &RollupType, batch_index: u64, - rollup_deployed_block: u64, + canonical_log_index: &Arc>, l1_provider: &Provider, ) -> Option<(CanonicalCommit, H256)> { - let commit = match resolve_canonical_commit(l1_rollup, l1_provider, batch_index, rollup_deployed_block, latest).await { + let mut canonical_log_index = canonical_log_index.lock().await; + if let Err(err) = canonical_log_index.refresh(l1_provider, l1_rollup.address(), latest, snapshot_hash).await { + log::error!("canonical Commit index refresh failed: {err:#}"); + return None; + } + let commit = match canonical_log_index.resolve(l1_rollup, batch_index, latest, snapshot_hash).await { Ok(Some(commit)) => commit, Ok(None) => { log::warn!("batch {batch_index} has no canonical Commit at snapshot {latest}"); @@ -392,6 +387,7 @@ async fn query_batch_tx( return None; } }; + drop(canonical_log_index); let block_id = BlockId::Number(BlockNumber::Number(latest)); let parent_index = batch_index.checked_sub(1)?; @@ -611,23 +607,20 @@ async fn send_transaction( contract: Address, calldata: Option, local_signer: &Arc, LocalWallet>>, - ext_signer: &Option, + proof_signer: &ApprovedProofSigner, l2_provider: &Provider, ) -> Result> { let req = Eip1559TransactionRequest::new().data(calldata.unwrap_or_default()); let mut tx = TypedTransaction::Eip1559(req); tx.set_to(contract); - if let Some(signer) = ext_signer { - tx.set_from(Address::from_str(&signer.address).unwrap_or_default()); - } else { - tx.set_from(local_signer.address()); - } + tx.set_from(proof_signer.address()); local_signer.fill_transaction(&mut tx, None).await.map_err(|e| { let msg = contract_error(ContractError::, LocalWallet>>::from_middleware_error(e)); anyhow!("prove_state fill_transaction error: {:#?}", msg) })?; - let signed_tx = sign_tx(tx, local_signer, ext_signer) + let signed_tx = proof_signer + .sign_transaction(&tx) .await .map_err(|e| anyhow!("prove_state sign_tx error: {}", e))?; @@ -650,19 +643,6 @@ async fn send_transaction( } } -async fn sign_tx( - tx: TypedTransaction, - local_signer: &Arc, LocalWallet>>, - ext_signer: &Option, -) -> Result> { - if let Some(signer) = ext_signer { - Ok(signer.request_sign(&tx).await?) - } else { - let signature = local_signer.signer().sign_transaction(&tx).await?; - Ok(tx.rlp_signed(&signature)) - } -} - pub fn contract_error(e: ContractError) -> String { let error_msg = if let Some(contract_err) = e.as_revert() { format!("contract error: {:?}", contract_err) diff --git a/prover/bin/challenge/src/lib.rs b/prover/bin/challenge/src/lib.rs index d5001864c..025c2c899 100644 --- a/prover/bin/challenge/src/lib.rs +++ b/prover/bin/challenge/src/lib.rs @@ -2,5 +2,6 @@ pub mod abi; mod external_sign; pub mod handler; pub mod metrics; +pub mod proof_signer; pub mod rollup_compat; pub mod util; diff --git a/prover/bin/challenge/src/main.rs b/prover/bin/challenge/src/main.rs index f134ac403..0d2919caa 100644 --- a/prover/bin/challenge/src/main.rs +++ b/prover/bin/challenge/src/main.rs @@ -54,6 +54,8 @@ fn register_metrics() { REGISTRY.register(Box::new(METRICS.verify_result.clone())).unwrap(); // wallet balance. REGISTRY.register(Box::new(METRICS.wallet_balance.clone())).unwrap(); + // approved active proof signer availability. + REGISTRY.register(Box::new(METRICS.proof_signer_available.clone())).unwrap(); } async fn handle_metrics() -> String { diff --git a/prover/bin/challenge/src/metrics.rs b/prover/bin/challenge/src/metrics.rs index 480d01f26..013918216 100644 --- a/prover/bin/challenge/src/metrics.rs +++ b/prover/bin/challenge/src/metrics.rs @@ -6,6 +6,7 @@ pub struct Metrics { pub blocks_len: IntGauge, pub verify_result: IntGauge, pub wallet_balance: Gauge, + pub proof_signer_available: IntGauge, } lazy_static! { @@ -15,5 +16,7 @@ lazy_static! { blocks_len: IntGauge::new("blocks_len", "blocks len").expect("blocks_len metric can be created"), verify_result: IntGauge::new("verify_result", "verify result").expect("verify metric can be created"), wallet_balance: Gauge::new("handler_wallet_balance", "handler wallet balance").expect("wallet metric can be created"), + proof_signer_available: IntGauge::new("proof_signer_available", "whether an approved proof signer is active") + .expect("proof signer metric can be created"), }; } diff --git a/prover/bin/challenge/src/proof_signer.rs b/prover/bin/challenge/src/proof_signer.rs new file mode 100644 index 000000000..9ead803a8 --- /dev/null +++ b/prover/bin/challenge/src/proof_signer.rs @@ -0,0 +1,155 @@ +use crate::abi::rollup_abi::Rollup; +use crate::external_sign::ExternalSign; +use crate::rollup_compat::authority_is_active; +use ethers::prelude::{BlockId, BlockNumber, LocalWallet, Middleware, Signer}; +use ethers::types::{transaction::eip2718::TypedTransaction, Address, Bytes, H256, U64}; +use eyre::{eyre, Result}; +use std::future::Future; + +#[derive(Clone)] +pub enum ApprovedProofSigner { + Local(LocalWallet), + External { address: Address, signer: Box }, +} + +impl ApprovedProofSigner { + pub fn local(wallet: LocalWallet) -> Self { + Self::Local(wallet) + } + + pub fn external(address: Address, signer: ExternalSign) -> Self { + Self::External { + address, + signer: Box::new(signer), + } + } + + pub fn address(&self) -> Address { + match self { + Self::Local(wallet) => wallet.address(), + Self::External { address, .. } => *address, + } + } + + pub async fn sign_transaction(&self, tx: &TypedTransaction) -> Result { + match self { + Self::Local(wallet) => { + let signature = wallet.sign_transaction(tx).await?; + Ok(tx.rlp_signed(&signature)) + } + Self::External { signer, .. } => signer.request_sign(tx).await.map_err(|err| eyre!(err.to_string())), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FixedSnapshot { + pub number: U64, + pub hash: H256, +} + +#[derive(Clone)] +pub struct SelectedProofSigner { + pub signer: ApprovedProofSigner, + pub approved_index: usize, + pub snapshot: FixedSnapshot, +} + +async fn first_active_index(approved: &[Address], mut is_active: F) -> std::result::Result, E> +where + F: FnMut(Address) -> Fut, + Fut: Future>, +{ + for (index, address) in approved.iter().copied().enumerate() { + if is_active(address).await? { + return Ok(Some(index)); + } + } + Ok(None) +} + +async fn fixed_finalized_snapshot(client: &M) -> Result { + let block = client + .get_block(BlockNumber::Finalized) + .await + .map_err(|err| eyre!("query finalized L1 snapshot failed: {err}"))? + .ok_or_else(|| eyre!("finalized L1 block is unavailable"))?; + let number = block.number.ok_or_else(|| eyre!("finalized L1 block has no number"))?; + let hash = block.hash.ok_or_else(|| eyre!("finalized L1 block has no hash"))?; + Ok(FixedSnapshot { number, hash }) +} + +async fn ensure_snapshot_unchanged(client: &M, snapshot: FixedSnapshot) -> Result<()> { + let current = client + .get_block(snapshot.number) + .await + .map_err(|err| eyre!("recheck finalized L1 snapshot failed: {err}"))? + .ok_or_else(|| eyre!("finalized L1 snapshot disappeared during signer selection"))?; + if current.hash != Some(snapshot.hash) { + return Err(eyre!("finalized L1 snapshot changed during signer selection")); + } + Ok(()) +} + +/// Selects the first approved signer that is active at one immutable finalized +/// block hash. The caller must treat `None` and every error as a hard no-send. +pub async fn select_active_proof_signer( + rollup: &Rollup, + approved: &[ApprovedProofSigner], +) -> Result> { + if approved.is_empty() { + return Err(eyre!("no approved proof signers are configured")); + } + + let snapshot = fixed_finalized_snapshot(rollup.client().as_ref()).await?; + let block_id = BlockId::Hash(snapshot.hash); + let addresses = approved.iter().map(ApprovedProofSigner::address).collect::>(); + let approved_index = first_active_index(&addresses, |address| async move { + authority_is_active(rollup, address, block_id) + .await + .map_err(|err| eyre!("active check failed for approved proof signer {address:?}: {err}")) + }) + .await?; + ensure_snapshot_unchanged(rollup.client().as_ref(), snapshot).await?; + Ok(approved_index.map(|approved_index| SelectedProofSigner { + signer: approved[approved_index].clone(), + approved_index, + snapshot, + })) +} + +#[cfg(test)] +mod tests { + use super::first_active_index; + use ethers::types::Address; + use std::convert::Infallible; + use std::future::ready; + + #[tokio::test] + async fn primary_inactivation_selects_first_active_backup() { + let primary = Address::from_low_u64_be(1); + let backup = Address::from_low_u64_be(2); + let approved = [primary, backup]; + + let initial = first_active_index(&approved, |_| ready(Ok::<_, Infallible>(true))).await.unwrap(); + let after_primary_inactivation = first_active_index(&approved, |address| ready(Ok::<_, Infallible>(address == backup))) + .await + .unwrap(); + + assert_eq!(initial, Some(0)); + assert_eq!(after_primary_inactivation, Some(1)); + } + + #[tokio::test] + async fn all_inactive_signers_fail_closed_without_dispatch() { + let approved = [Address::from_low_u64_be(1), Address::from_low_u64_be(2)]; + let selected = first_active_index(&approved, |_| ready(Ok::<_, Infallible>(false))).await.unwrap(); + let mut sent_transactions = 0; + if selected.is_some() { + sent_transactions += 1; + } + + assert_eq!(selected, None); + assert_eq!(sent_transactions, 0); + } +} diff --git a/prover/bin/challenge/src/rollup_compat.rs b/prover/bin/challenge/src/rollup_compat.rs index fc0875cbe..8ea74f73e 100644 --- a/prover/bin/challenge/src/rollup_compat.rs +++ b/prover/bin/challenge/src/rollup_compat.rs @@ -5,6 +5,7 @@ use ethers::{ utils::{id, keccak256}, }; use eyre::{eyre, Result}; +use std::collections::HashMap; use crate::abi::{ legacy_l1_staking_abi::LegacyL1Staking, @@ -221,80 +222,221 @@ pub fn select_canonical_commit(commits: &[Log], reverts: &[Log], canonical_hash: const QUERY_RANGE: u64 = 10_000; -pub async fn resolve_canonical_commit( - rollup: &Rollup, - provider: &P, - batch_index: u64, +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct IndexedSnapshot { + number: u64, + hash: H256, +} + +/// Reusable finalized Commit/Revert index. The first poll replays from the +/// configured Rollup deployment block; subsequent polls validate the previous +/// block-hash anchor and query only the newly finalized suffix. +#[derive(Debug)] +pub struct CanonicalLogIndex { rollup_deployed_block: u64, - snapshot_number: U64, -) -> Result> -where - M: Middleware + 'static, - P: Middleware + 'static, -{ - if rollup_deployed_block == 0 || rollup_deployed_block > snapshot_number.as_u64() { - return Err(eyre!( - "invalid Rollup deployment block {rollup_deployed_block} for snapshot {snapshot_number}" - )); - } - let before = provider - .get_block(snapshot_number) - .await? - .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; - let before_hash = before.hash.ok_or_else(|| eyre!("snapshot block has no hash"))?; - let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); - let canonical_hash: H256 = rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?.into(); - if canonical_hash.is_zero() { - return Ok(None); - } - - let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); - let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); - let mut commits = Vec::new(); - let mut reverts = Vec::new(); - let mut from = rollup_deployed_block; - while from <= snapshot_number.as_u64() { - let to = from.saturating_add(QUERY_RANGE - 1).min(snapshot_number.as_u64()); - let base = Filter::new() - .address(rollup.address()) - .from_block(from) - .to_block(to) - .topic1(U256::from(batch_index)); - commits.extend(provider.get_logs(&base.clone().topic0(commit_topic)).await?); - reverts.extend(provider.get_logs(&base.topic0(revert_topic)).await?); - if to == snapshot_number.as_u64() { - break; + indexed_snapshot: Option, + commits: HashMap>, + reverts: HashMap>, +} + +impl CanonicalLogIndex { + pub fn new(rollup_deployed_block: u64) -> Result { + if rollup_deployed_block == 0 { + return Err(eyre!("Rollup deployment block must be non-zero")); + } + Ok(Self { + rollup_deployed_block, + indexed_snapshot: None, + commits: HashMap::new(), + reverts: HashMap::new(), + }) + } + + fn clear(&mut self) { + self.indexed_snapshot = None; + self.commits.clear(); + self.reverts.clear(); + } + + fn query_start(&self, snapshot_number: u64) -> Result> { + if snapshot_number < self.rollup_deployed_block { + return Err(eyre!( + "Rollup deployment block {} is newer than snapshot {snapshot_number}", + self.rollup_deployed_block + )); + } + match self.indexed_snapshot { + None => Ok(Some(self.rollup_deployed_block)), + Some(indexed) if snapshot_number < indexed.number => Err(eyre!( + "finalized snapshot moved backwards: indexed={}, requested={snapshot_number}", + indexed.number + )), + Some(indexed) if snapshot_number == indexed.number => Ok(None), + Some(indexed) => Ok(Some( + indexed.number.checked_add(1).ok_or_else(|| eyre!("canonical log index block overflow"))?, + )), + } + } + + fn verify_cached_anchor(&mut self, observed_hash: H256) -> Result<()> { + let Some(indexed) = self.indexed_snapshot else { + return Ok(()); + }; + if indexed.hash != observed_hash { + self.clear(); + return Err(eyre!("canonical log index anchor changed at block {}; cache discarded", indexed.number)); + } + Ok(()) + } + + fn batch_index(log: &Log) -> Result { + if log.removed.unwrap_or_default() { + return Err(eyre!("removed log returned for finalized canonical range")); + } + identity(log).ok_or_else(|| eyre!("canonical Rollup log has incomplete identity"))?; + if log.transaction_hash.is_none() || log.block_hash.is_none() { + return Err(eyre!("canonical Rollup log has incomplete block/transaction identity")); + } + if log.topics.len() < 3 { + return Err(eyre!("canonical Rollup log is missing indexed topics")); + } + let batch_index = U256::from_big_endian(log.topics[1].as_bytes()); + if batch_index > U256::from(u64::MAX) { + return Err(eyre!("Rollup batch index exceeds u64")); + } + Ok(batch_index.as_u64()) + } + + fn append_logs(&mut self, snapshot_number: u64, snapshot_hash: H256, commits: Vec, reverts: Vec) -> Result<()> { + let mut indexed_commits = Vec::with_capacity(commits.len()); + for log in commits { + indexed_commits.push((Self::batch_index(&log)?, log)); + } + let mut indexed_reverts = Vec::with_capacity(reverts.len()); + for log in reverts { + indexed_reverts.push((Self::batch_index(&log)?, log)); + } + for (batch_index, log) in indexed_commits { + self.commits.entry(batch_index).or_default().push(log); } - from = to + 1; + for (batch_index, log) in indexed_reverts { + self.reverts.entry(batch_index).or_default().push(log); + } + self.indexed_snapshot = Some(IndexedSnapshot { + number: snapshot_number, + hash: snapshot_hash, + }); + Ok(()) + } + + fn resolve_cached(&self, batch_index: u64, canonical_hash: H256) -> Option { + select_canonical_commit( + self.commits.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), + self.reverts.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), + canonical_hash, + ) } - let after = provider - .get_block(snapshot_number) - .await? - .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; - if after.hash != Some(before_hash) { - return Err(eyre!("snapshot block hash changed during canonical resolution")); + pub async fn refresh(&mut self, provider: &P, rollup: Address, snapshot_number: U64, snapshot_hash: H256) -> Result<()> { + let before = provider + .get_block(snapshot_number) + .await? + .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; + if before.hash != Some(snapshot_hash) { + return Err(eyre!("finalized snapshot hash changed before canonical log refresh")); + } + + if let Some(indexed) = self.indexed_snapshot { + let anchor = provider + .get_block(U64::from(indexed.number)) + .await? + .ok_or_else(|| eyre!("canonical log index anchor block disappeared"))?; + let anchor_hash = anchor.hash.ok_or_else(|| eyre!("canonical log index anchor has no hash"))?; + self.verify_cached_anchor(anchor_hash)?; + } + + let query_start = match self.query_start(snapshot_number.as_u64()) { + Ok(query_start) => query_start, + Err(error) => { + self.clear(); + return Err(error); + } + }; + let Some(mut from) = query_start else { + self.verify_cached_anchor(snapshot_hash)?; + return Ok(()); + }; + + let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); + let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); + let mut commits = Vec::new(); + let mut reverts = Vec::new(); + while from <= snapshot_number.as_u64() { + let to = from.saturating_add(QUERY_RANGE - 1).min(snapshot_number.as_u64()); + let base = Filter::new().address(rollup).from_block(from).to_block(to); + commits.extend(provider.get_logs(&base.clone().topic0(commit_topic)).await?); + reverts.extend(provider.get_logs(&base.topic0(revert_topic)).await?); + if to == snapshot_number.as_u64() { + break; + } + from = to.checked_add(1).ok_or_else(|| eyre!("canonical log query block overflow"))?; + } + + let after = provider + .get_block(snapshot_number) + .await? + .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; + if after.hash != Some(snapshot_hash) { + return Err(eyre!("snapshot block hash changed during canonical log refresh")); + } + + self.append_logs(snapshot_number.as_u64(), snapshot_hash, commits, reverts) } - Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) + pub async fn resolve( + &self, + rollup: &Rollup, + batch_index: u64, + snapshot_number: U64, + snapshot_hash: H256, + ) -> Result> { + if self.indexed_snapshot + != Some(IndexedSnapshot { + number: snapshot_number.as_u64(), + hash: snapshot_hash, + }) + { + return Err(eyre!("canonical log index is not anchored to the requested snapshot")); + } + let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); + let canonical_hash: H256 = rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?.into(); + if canonical_hash.is_zero() { + return Ok(None); + } + Ok(self.resolve_cached(batch_index, canonical_hash)) + } } #[cfg(test)] mod tests { use super::*; - fn log(block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { + fn batch_log(batch: u64, block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { Log { block_number: Some(block.into()), transaction_index: Some(tx.into()), log_index: Some(index.into()), transaction_hash: Some(H256::from_low_u64_be(marker)), block_hash: Some(H256::from_low_u64_be(block)), - topics: vec![H256::zero(), H256::from_low_u64_be(7), hash], + topics: vec![H256::zero(), H256::from_low_u64_be(batch), hash], ..Default::default() } } + fn log(block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { + batch_log(7, block, tx, index, hash, marker) + } + #[test] fn rejects_short_and_unknown_calldata() { assert!(decode_batch_data_input(&[]).is_err()); @@ -357,4 +499,48 @@ mod tests { assert_eq!(decode_batch_data_store_block_number(&old_tuple).unwrap(), U256::from(123)); assert!(decode_batch_data_store_block_number(&old_tuple[..127]).is_err()); } + + #[test] + fn canonical_log_index_reuses_snapshot_and_only_plans_new_suffix() { + let snapshot_hash = H256::from_low_u64_be(100); + let mut index = CanonicalLogIndex::new(5).unwrap(); + assert_eq!(index.query_start(10).unwrap(), Some(5)); + + let hash7 = H256::from_low_u64_be(7); + let hash8 = H256::from_low_u64_be(8); + index + .append_logs( + 10, + snapshot_hash, + vec![batch_log(7, 7, 0, 0, hash7, 7), batch_log(8, 8, 0, 0, hash8, 8)], + vec![], + ) + .unwrap(); + + assert!(index.resolve_cached(7, hash7).is_some()); + assert!(index.resolve_cached(8, hash8).is_some()); + assert_eq!(index.query_start(10).unwrap(), None); + assert_eq!(index.query_start(12).unwrap(), Some(11)); + + let hash9 = H256::from_low_u64_be(9); + index + .append_logs(12, H256::from_low_u64_be(102), vec![batch_log(9, 11, 0, 0, hash9, 9)], vec![]) + .unwrap(); + assert!(index.resolve_cached(7, hash7).is_some()); + assert!(index.resolve_cached(9, hash9).is_some()); + } + + #[test] + fn canonical_log_index_discards_cache_and_fails_closed_on_anchor_reorg() { + let old_hash = H256::from_low_u64_be(100); + let mut index = CanonicalLogIndex::new(5).unwrap(); + index + .append_logs(10, old_hash, vec![batch_log(7, 7, 0, 0, H256::from_low_u64_be(7), 7)], vec![]) + .unwrap(); + + let error = index.verify_cached_anchor(H256::from_low_u64_be(101)).unwrap_err(); + assert!(error.to_string().contains("cache discarded")); + assert!(index.resolve_cached(7, H256::from_low_u64_be(7)).is_none()); + assert_eq!(index.query_start(12).unwrap(), Some(5)); + } } diff --git a/prover/bin/shadow-prove/src/rollup_compat.rs b/prover/bin/shadow-prove/src/rollup_compat.rs index 5a2fd5a3f..992eb2f09 100644 --- a/prover/bin/shadow-prove/src/rollup_compat.rs +++ b/prover/bin/shadow-prove/src/rollup_compat.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use alloy_primitives::{Bytes, TxHash, B256, U256}; use alloy_provider::{DynProvider, Provider}; use alloy_rpc_types::{BlockId, BlockNumberOrTag, Log}; @@ -90,75 +92,238 @@ pub fn select_canonical_commit( const LOG_QUERY_BLOCK_RANGE: u64 = 10_000; -/// Resolve a batch's canonical Commit using one numbered snapshot. The block -/// hash is checked before and after all getter/log reads so RPCs without -/// EIP-1898 support cannot silently combine different forks. -pub async fn resolve_canonical_commit( - provider: &DynProvider, - rollup: &RollupInstance, - batch_index: u64, +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct IndexedSnapshot { + number: u64, + hash: B256, +} + +/// A reusable Commit/Revert index anchored to one canonical finalized block. +/// +/// The first refresh replays from the configured Rollup deployment block. A +/// later refresh first verifies the previous anchor and then scans only the +/// newly finalized suffix. If the anchor changed, the cache is discarded and +/// the current operation fails closed; a later poll may rebuild from genesis. +#[derive(Debug)] +pub struct CanonicalLogIndex { rollup_deployed_block: u64, - snapshot_number: u64, -) -> Result> { - if rollup_deployed_block == 0 || rollup_deployed_block > snapshot_number { - return Err(anyhow!( - "invalid Rollup deployment block {rollup_deployed_block} for snapshot {snapshot_number}" - )); + indexed_snapshot: Option, + commits: HashMap>, + reverts: HashMap>, +} + +impl CanonicalLogIndex { + pub fn new(rollup_deployed_block: u64) -> Result { + if rollup_deployed_block == 0 { + return Err(anyhow!("Rollup deployment block must be non-zero")); + } + Ok(Self { + rollup_deployed_block, + indexed_snapshot: None, + commits: HashMap::new(), + reverts: HashMap::new(), + }) } - let snapshot_tag = BlockNumberOrTag::Number(snapshot_number); - let before = provider - .get_block_by_number(snapshot_tag) - .await? - .ok_or_else(|| anyhow!("snapshot block {snapshot_number} not found"))?; - let before_hash = before.header.hash; - - let canonical_hash = rollup - .committedBatches(U256::from(batch_index)) - .block(BlockId::Number(snapshot_tag)) - .call() - .await?; - if canonical_hash == B256::ZERO { - return Ok(None); + + fn clear(&mut self) { + self.indexed_snapshot = None; + self.commits.clear(); + self.reverts.clear(); } - let mut commits = Vec::new(); - let mut reverts = Vec::new(); - let mut from = rollup_deployed_block; - while from <= snapshot_number { - let to = from.saturating_add(LOG_QUERY_BLOCK_RANGE - 1).min(snapshot_number); - let commit_filter = rollup - .CommitBatch_filter() - .filter - .from_block(from) - .to_block(to) - .topic1(U256::from(batch_index)) - .address(*rollup.address()); - commits.extend(provider.get_logs(&commit_filter).await?); - - let revert_filter = rollup - .RevertBatch_filter() - .filter - .from_block(from) - .to_block(to) - .topic1(U256::from(batch_index)) - .address(*rollup.address()); - reverts.extend(provider.get_logs(&revert_filter).await?); - - if to == snapshot_number { - break; + fn query_start(&self, snapshot_number: u64) -> Result> { + if snapshot_number < self.rollup_deployed_block { + return Err(anyhow!( + "Rollup deployment block {} is newer than snapshot {snapshot_number}", + self.rollup_deployed_block + )); + } + match self.indexed_snapshot { + None => Ok(Some(self.rollup_deployed_block)), + Some(indexed) if snapshot_number < indexed.number => Err(anyhow!( + "finalized snapshot moved backwards: indexed={}, requested={snapshot_number}", + indexed.number + )), + Some(indexed) if snapshot_number == indexed.number => Ok(None), + Some(indexed) => Ok(Some( + indexed + .number + .checked_add(1) + .ok_or_else(|| anyhow!("canonical log index block overflow"))?, + )), } - from = to + 1; } - let after = provider - .get_block_by_number(snapshot_tag) - .await? - .ok_or_else(|| anyhow!("snapshot block {snapshot_number} disappeared"))?; - if after.header.hash != before_hash { - return Err(anyhow!("snapshot block hash changed during canonical resolution")); + fn verify_cached_anchor(&mut self, observed_hash: B256) -> Result<()> { + let Some(indexed) = self.indexed_snapshot else { + return Ok(()); + }; + if indexed.hash != observed_hash { + self.clear(); + return Err(anyhow!( + "canonical log index anchor changed at block {}; cache discarded", + indexed.number + )); + } + Ok(()) } - Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) + fn batch_index(log: &Log) -> Result { + if log.removed { + return Err(anyhow!("removed log returned for finalized canonical range")); + } + // Require every component used by canonical identity before admitting a + // log to the cache. Resolution must never silently skip malformed RPC + // results and fall back to an older Commit. + log_identity(log).ok_or_else(|| anyhow!("canonical Rollup log has incomplete identity"))?; + if log.transaction_hash.is_none() || log.block_hash.is_none() { + return Err(anyhow!("canonical Rollup log has incomplete block/transaction identity")); + } + let topics = log.topics(); + if topics.len() < 3 { + return Err(anyhow!("canonical Rollup log is missing indexed topics")); + } + let batch_index = U256::from_be_slice(topics[1].as_slice()); + if batch_index > U256::from(u64::MAX) { + return Err(anyhow!("Rollup batch index exceeds u64")); + } + Ok(batch_index.to::()) + } + + fn append_logs( + &mut self, + snapshot_number: u64, + snapshot_hash: B256, + commits: Vec, + reverts: Vec, + ) -> Result<()> { + let mut indexed_commits = Vec::with_capacity(commits.len()); + for log in commits { + indexed_commits.push((Self::batch_index(&log)?, log)); + } + let mut indexed_reverts = Vec::with_capacity(reverts.len()); + for log in reverts { + indexed_reverts.push((Self::batch_index(&log)?, log)); + } + for (batch_index, log) in indexed_commits { + self.commits.entry(batch_index).or_default().push(log); + } + for (batch_index, log) in indexed_reverts { + self.reverts.entry(batch_index).or_default().push(log); + } + self.indexed_snapshot = + Some(IndexedSnapshot { number: snapshot_number, hash: snapshot_hash }); + Ok(()) + } + + fn resolve_cached(&self, batch_index: u64, canonical_hash: B256) -> Option { + select_canonical_commit( + self.commits.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), + self.reverts.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), + canonical_hash, + ) + } + + pub async fn refresh( + &mut self, + provider: &DynProvider, + rollup: &RollupInstance, + snapshot_number: u64, + snapshot_hash: B256, + ) -> Result<()> { + let snapshot_tag = BlockNumberOrTag::Number(snapshot_number); + let before = provider + .get_block_by_number(snapshot_tag) + .await? + .ok_or_else(|| anyhow!("snapshot block {snapshot_number} not found"))?; + if before.header.hash != snapshot_hash { + return Err(anyhow!("finalized snapshot hash changed before canonical log refresh")); + } + + if let Some(indexed) = self.indexed_snapshot { + let anchor = provider + .get_block_by_number(BlockNumberOrTag::Number(indexed.number)) + .await? + .ok_or_else(|| anyhow!("canonical log index anchor block disappeared"))?; + self.verify_cached_anchor(anchor.header.hash)?; + } + + let query_start = match self.query_start(snapshot_number) { + Ok(query_start) => query_start, + Err(error) => { + self.clear(); + return Err(error); + } + }; + let Some(mut from) = query_start else { + // Equal-height reuse still verifies the caller supplied the exact + // cached block hash, rather than merely the block number. + self.verify_cached_anchor(snapshot_hash)?; + return Ok(()); + }; + + let mut commits = Vec::new(); + let mut reverts = Vec::new(); + while from <= snapshot_number { + let to = from.saturating_add(LOG_QUERY_BLOCK_RANGE - 1).min(snapshot_number); + let commit_filter = rollup + .CommitBatch_filter() + .filter + .from_block(from) + .to_block(to) + .address(*rollup.address()); + commits.extend(provider.get_logs(&commit_filter).await?); + + let revert_filter = rollup + .RevertBatch_filter() + .filter + .from_block(from) + .to_block(to) + .address(*rollup.address()); + reverts.extend(provider.get_logs(&revert_filter).await?); + + if to == snapshot_number { + break; + } + from = + to.checked_add(1).ok_or_else(|| anyhow!("canonical log query block overflow"))?; + } + + let after = provider + .get_block_by_number(snapshot_tag) + .await? + .ok_or_else(|| anyhow!("snapshot block {snapshot_number} disappeared"))?; + if after.header.hash != snapshot_hash { + return Err(anyhow!("snapshot block hash changed during canonical log refresh")); + } + + self.append_logs(snapshot_number, snapshot_hash, commits, reverts) + } + + /// Resolve from the already-refreshed fixed snapshot. Multiple batch + /// lookups (shadow prev/current/next) reuse the same log replay. + pub async fn resolve( + &self, + rollup: &RollupInstance, + batch_index: u64, + snapshot_number: u64, + snapshot_hash: B256, + ) -> Result> { + if self.indexed_snapshot != + Some(IndexedSnapshot { number: snapshot_number, hash: snapshot_hash }) + { + return Err(anyhow!("canonical log index is not anchored to the requested snapshot")); + } + let canonical_hash = rollup + .committedBatches(U256::from(batch_index)) + .block(BlockId::Number(BlockNumberOrTag::Number(snapshot_number))) + .call() + .await?; + if canonical_hash == B256::ZERO { + return Ok(None); + } + Ok(self.resolve_cached(batch_index, canonical_hash)) + } } fn current_input(input: IRollup::BatchDataInput, kind: SubmissionKind) -> BatchDataInput { @@ -331,4 +496,59 @@ mod tests { let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); assert_eq!(resolved.transaction_hash, B256::repeat_byte(3)); } + + #[test] + fn canonical_log_index_reuses_one_snapshot_for_adjacent_batches_and_then_increments() { + let snapshot_hash = B256::repeat_byte(0xaa); + let mut index = CanonicalLogIndex::new(5).unwrap(); + assert_eq!(index.query_start(10).unwrap(), Some(5)); + + let hash6 = B256::repeat_byte(6); + let hash7 = B256::repeat_byte(7); + let hash8 = B256::repeat_byte(8); + index + .append_logs( + 10, + snapshot_hash, + vec![ + rpc_log(6, hash6, 6, 0, 0, 6), + rpc_log(7, hash7, 7, 0, 0, 7), + rpc_log(8, hash8, 8, 0, 0, 8), + ], + vec![], + ) + .unwrap(); + + // prev/current/next are all served by the same indexed replay. + assert_eq!(index.resolve_cached(6, hash6).unwrap().identity.block_number, 6); + assert_eq!(index.resolve_cached(7, hash7).unwrap().identity.block_number, 7); + assert_eq!(index.resolve_cached(8, hash8).unwrap().identity.block_number, 8); + assert_eq!(index.query_start(10).unwrap(), None); + assert_eq!(index.query_start(12).unwrap(), Some(11)); + + index + .append_logs( + 12, + B256::repeat_byte(0xbb), + vec![rpc_log(9, B256::repeat_byte(9), 11, 0, 0, 9)], + vec![], + ) + .unwrap(); + assert!(index.resolve_cached(7, hash7).is_some()); + assert!(index.resolve_cached(9, B256::repeat_byte(9)).is_some()); + } + + #[test] + fn canonical_log_index_discards_cache_and_fails_closed_on_anchor_reorg() { + let old_hash = B256::repeat_byte(0xaa); + let mut index = CanonicalLogIndex::new(5).unwrap(); + index + .append_logs(10, old_hash, vec![rpc_log(7, B256::repeat_byte(7), 7, 0, 0, 7)], vec![]) + .unwrap(); + + let error = index.verify_cached_anchor(B256::repeat_byte(0xbb)).unwrap_err(); + assert!(error.to_string().contains("cache discarded")); + assert!(index.resolve_cached(7, B256::repeat_byte(7)).is_none()); + assert_eq!(index.query_start(12).unwrap(), Some(5)); + } } diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index 3aa4f4c55..5dc88264b 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -7,11 +7,11 @@ use alloy_rpc_types::{BlockId, BlockNumberOrTag}; use anyhow::{anyhow, Context, Result}; use futures::future::join_all; +use std::sync::Arc; +use tokio::sync::Mutex; use crate::{ - rollup_compat::{ - decode_batch_data_input, resolve_canonical_commit, BatchDataInput, CanonicalCommit, - }, + rollup_compat::{decode_batch_data_input, BatchDataInput, CanonicalCommit, CanonicalLogIndex}, Rollup::{self, RollupInstance}, ShadowRollup::{self, ShadowRollupInstance}, }; @@ -22,7 +22,7 @@ pub struct BatchSyncer { l2_provider: DynProvider, l1_rollup: RollupInstance, l1_shadow_rollup: ShadowRollupInstance, - rollup_deployed_block: u64, + canonical_log_index: Arc>, } impl BatchSyncer @@ -64,8 +64,12 @@ where ) -> Self { let l1_rollup = Rollup::RollupInstance::new(rollup_address, l1_provider.clone()); let l1_shadow_rollup = ShadowRollup::new(shadow_rollup_address, wallet); + let canonical_log_index = Arc::new(Mutex::new( + CanonicalLogIndex::new(rollup_deployed_block) + .expect("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK must be non-zero"), + )); - Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup, rollup_deployed_block } + Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup, canonical_log_index } } // Fetch the latest committed batch from l1-rollup if the batch_index has increased. @@ -131,32 +135,20 @@ where } self.assert_snapshot(snapshot, snapshot_hash).await?; - let prev = resolve_canonical_commit( - &self.l1_provider, - &self.l1_rollup, - batch_num - 1, - self.rollup_deployed_block, - snapshot, - ) - .await?; - self.assert_snapshot(snapshot, snapshot_hash).await?; - let current = resolve_canonical_commit( - &self.l1_provider, - &self.l1_rollup, - batch_num, - self.rollup_deployed_block, - snapshot, - ) - .await?; - self.assert_snapshot(snapshot, snapshot_hash).await?; - let next = resolve_canonical_commit( - &self.l1_provider, - &self.l1_rollup, - batch_num + 1, - self.rollup_deployed_block, - snapshot, - ) - .await?; + let mut canonical_log_index = self.canonical_log_index.lock().await; + canonical_log_index + .refresh(&self.l1_provider, &self.l1_rollup, snapshot, snapshot_hash) + .await?; + let prev = canonical_log_index + .resolve(&self.l1_rollup, batch_num - 1, snapshot, snapshot_hash) + .await?; + let current = canonical_log_index + .resolve(&self.l1_rollup, batch_num, snapshot, snapshot_hash) + .await?; + let next = canonical_log_index + .resolve(&self.l1_rollup, batch_num + 1, snapshot, snapshot_hash) + .await?; + drop(canonical_log_index); self.assert_snapshot(snapshot, snapshot_hash).await?; let (Some(prev), Some(current), Some(next)) = (prev, current, next) else { return Ok(None); From b755899f319b1192b77743573676ea662cb6b0f9 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 05:34:11 +0800 Subject: [PATCH 17/38] revert: remove previous centralization cleanup implementation --- .github/workflows/bindings.yml | 60 - .github/workflows/cherry-pick.yml | 4 +- .github/workflows/common.yml | 37 - .github/workflows/contracts.yml | 21 +- .github/workflows/deployer.yml | 9 +- .github/workflows/gas-oracle.yml | 22 +- .github/workflows/node.yml | 9 +- .github/workflows/ops.yml | 52 - .github/workflows/prover.yml | 35 +- .github/workflows/tx-submitter.yml | 12 +- bindings/Makefile | 11 +- bindings/bin/l1staking_deployed.hex | 1 + bindings/bin/rollup_deployed.hex | 2 +- bindings/bin/submitter_deployed.hex | 1 - .../bindings/centralization_cleanup_test.go | 237 -- bindings/bindings/l1staking.go | 3445 +++++++++++++++++ bindings/bindings/l1staking_more.go | 25 + bindings/bindings/rollup.go | 408 +- bindings/bindings/rollup_more.go | 4 +- bindings/bindings/submitter.go | 2863 -------------- bindings/bindings/submitter_more.go | 25 - bindings/compile.sh | 35 +- bindings/gen_bindings.sh | 5 +- build/lint.go | 2 +- common/batch/batch_cache.go | 351 +- .../batch/batch_cache_genesis_header_test.go | 10 +- common/batch/batch_cache_test.go | 9 +- common/batch/batch_header.go | 20 +- common/batch/batch_header_zero_test.go | 36 - common/batch/batch_query.go | 989 ++--- common/batch/batch_query_test.go | 129 - common/batch/batch_restart_test.go | 492 ++- common/batch/batch_storage_test.go | 2 +- common/batch/canonical_bootstrap_test.go | 386 -- common/batch/commit_test.go | 19 +- common/batch/config.go | 39 - common/batch/config_test.go | 36 - common/batch/helpers_test.go | 9 - common/batch/interfaces.go | 21 +- common/batch/l2_gov.go | 51 +- common/batch/snapshot.go | 101 - contracts/abi/archive/README.md | 13 - .../archive/legacy-l1-staking/IL1Staking.json | 1 - .../archive/legacy-l1-staking/L1Staking.json | 1033 ----- contracts/abi/archive/manifest.json | 14 - .../abi/archive/pre-submitter/Rollup.json | 1416 ------- contracts/contracts/Staking.md | 134 + contracts/contracts/l1/rollup/BLS.sol | 4 + contracts/contracts/l1/rollup/IRollup.sol | 39 +- contracts/contracts/l1/rollup/ISubmitter.sol | 18 - contracts/contracts/l1/rollup/Rollup.sol | 193 +- contracts/contracts/l1/rollup/Submitter.sol | 221 -- contracts/contracts/l1/staking/IL1Staking.sol | 119 + contracts/contracts/l1/staking/L1Staking.sol | 515 +++ contracts/contracts/test/L1Staking.t.sol | 1154 ++++++ contracts/contracts/test/Rollup.t.sol | 591 +-- contracts/contracts/test/Submitter.t.sol | 461 --- .../contracts/test/base/L1MessageBase.t.sol | 41 +- contracts/deploy/013-DeployProxys.ts | 10 +- contracts/deploy/014-DeployImpls.ts | 43 +- contracts/deploy/015-SubmitterInstall.ts | 109 - contracts/deploy/016-RollupInit.ts | 10 +- contracts/deploy/018-StakingInit.ts | 128 + contracts/deploy/019-AdminTransfer.ts | 10 +- contracts/deploy/020-ContractInit.ts | 44 +- contracts/deploy/021-StakingRegister.ts | 57 + contracts/deploy/021-SubmitterRegister.ts | 38 - contracts/deploy/index.ts | 10 +- contracts/hardhat.config.ts | 8 +- .../retire-l1-staking.spec.ts | 122 - .../integration-test/submitter-deploy.spec.ts | 72 - .../legacy-l1-staking-retirement.example.json | 18 - contracts/package.json | 3 +- contracts/scripts/clean-generated-abi.js | 16 - contracts/scripts/retire-l1-staking.ts | 664 ---- contracts/scripts/verify-abi-archive.js | 36 - contracts/src/deploy-config/holesky.ts | 16 +- contracts/src/deploy-config/hoodi.ts | 16 +- contracts/src/deploy-config/l1.ts | 16 +- contracts/src/deploy-config/qanetl1.ts | 16 +- contracts/src/deploy-config/sepolia.ts | 8 +- contracts/src/deploy-config/testnetl1.ts | 8 +- contracts/src/deploy-utils.ts | 5 +- contracts/src/types.ts | 15 +- .../archive/Rollup.pre-submitter.json | 424 -- contracts/tasks/deploy.ts | 54 +- contracts/tasks/staking_upgrade.ts | 901 +++++ gas-oracle/.env.dev | 5 +- gas-oracle/Makefile | 8 +- gas-oracle/app/Cargo.lock | 74 +- gas-oracle/app/Cargo.toml | 1 - gas-oracle/app/rust-toolchain | 2 +- gas-oracle/app/rustfmt.toml | 8 + gas-oracle/app/src/abi/Rollup.json | 288 +- gas-oracle/app/src/abi/mod.rs | 5 - .../app/src/abi/pre_submitter/Rollup.json | 1416 ------- gas-oracle/app/src/da_scalar/blob.rs | 8 +- gas-oracle/app/src/da_scalar/blob_client.rs | 8 +- gas-oracle/app/src/da_scalar/calculate.rs | 239 +- gas-oracle/app/src/da_scalar/error.rs | 1 + gas-oracle/app/src/da_scalar/l1_scalar.rs | 975 +---- gas-oracle/app/src/da_scalar/mod.rs | 2 +- gas-oracle/app/src/gas_price_oracle.rs | 12 +- gas-oracle/app/src/l1_base_fee.rs | 9 +- gas-oracle/app/src/lib.rs | 3 +- gas-oracle/app/src/metrics.rs | 8 +- gas-oracle/app/src/rollup_compat.rs | 299 -- gas-oracle/app/src/signer.rs | 5 +- node/cmd/node/main.go | 60 +- node/core/centralization_cleanup_test.go | 113 - node/core/config.go | 60 +- node/core/executor.go | 92 +- node/core/sequencers.go | 42 +- node/derivation/calldata_fixture_test.go | 199 - node/derivation/canonical_commit.go | 376 -- node/derivation/canonical_commit_test.go | 225 -- node/derivation/config.go | 5 + node/derivation/config_test.go | 26 + node/derivation/derivation.go | 257 +- node/derivation/derivation_test.go | 3 - .../testdata/rollup_calldata_fixtures.json | 123 - node/flags/flags.go | 17 +- node/go.mod | 2 +- node/ops-morph/docker-compose.yml | 4 +- node/ops-morph/testnet/docker-compose.yml | 8 +- node/ops-morph/testnet/launch.sh | 9 +- node/types/abi/pre_submitter_rollup.json | 1416 ------- node/types/batch.go | 10 - ops/devnet-morph/devnet/__init__.py | 100 +- ops/devnet-morph/tests/test_devnet_config.py | 36 - ops/docker/.env | 8 +- ops/docker/Dockerfile.oracle | 8 +- ops/docker/docker-compose-cluster.yml | 3 - ops/docker/docker-compose-devnet.yml | 11 +- prover/Makefile | 6 +- prover/bin/challenge/.env.dev | 8 - prover/bin/challenge/src/abi/Rollup.json | 288 +- prover/bin/challenge/src/abi/Submitter.json | 660 ---- prover/bin/challenge/src/abi/mod.rs | 15 - .../abi/pre_submitter/LegacyL1Staking.json | 34 - .../src/abi/pre_submitter/Rollup.json | 1416 ------- .../bin/challenge/src/bin/auto_challenge.rs | 110 +- prover/bin/challenge/src/external_sign.rs | 3 +- prover/bin/challenge/src/handler.rs | 318 +- prover/bin/challenge/src/lib.rs | 5 +- prover/bin/challenge/src/main.rs | 2 - prover/bin/challenge/src/metrics.rs | 3 - prover/bin/challenge/src/proof_signer.rs | 155 - prover/bin/challenge/src/rollup_compat.rs | 546 --- prover/bin/challenge/src/util.rs | 1 - prover/bin/shadow-prove/.env.dev | 5 +- prover/bin/shadow-prove/abi/Rollup.json | 196 +- .../abi/pre_submitter/Rollup.json | 1416 ------- prover/bin/shadow-prove/src/abi.rs | 10 - prover/bin/shadow-prove/src/execute.rs | 10 +- prover/bin/shadow-prove/src/lib.rs | 1 - prover/bin/shadow-prove/src/main.rs | 12 +- prover/bin/shadow-prove/src/rollup_compat.rs | 554 --- prover/bin/shadow-prove/src/shadow_prove.rs | 21 +- prover/bin/shadow-prove/src/shadow_rollup.rs | 517 ++- prover/bin/shadow-prove/src/util.rs | 1 - tx-submitter/README.md | 5 +- tx-submitter/constants/methods.go | 7 +- tx-submitter/entry.go | 55 +- tx-submitter/event/indexer.go | 145 + tx-submitter/event/storage.go | 109 + tx-submitter/event/storage_test.go | 40 + tx-submitter/flags/flags.go | 95 +- tx-submitter/iface/client.go | 8 +- tx-submitter/iface/rollup.go | 35 +- tx-submitter/mock/event_storage.go | 26 + tx-submitter/mock/l1staking.go | 62 + tx-submitter/mock/l2client.go | 42 + tx-submitter/mock/rollup.go | 50 +- tx-submitter/mock/submitter.go | 63 - tx-submitter/params/leveldb_keys.go | 5 + tx-submitter/services/batch_fecher.go | 3 +- tx-submitter/services/pendingtx.go | 56 +- tx-submitter/services/pendingtx_test.go | 76 - tx-submitter/services/rollup.go | 586 ++- tx-submitter/services/rollup_handle_test.go | 91 +- tx-submitter/services/rollup_test.go | 36 +- tx-submitter/services/rotator.go | 158 + tx-submitter/types/batch_cache.go | 19 +- tx-submitter/utils/config.go | 105 +- tx-submitter/utils/config_test.go | 40 - tx-submitter/utils/utils.go | 126 +- tx-submitter/utils/utils_test.go | 4 +- 188 files changed, 10477 insertions(+), 23341 deletions(-) delete mode 100644 .github/workflows/bindings.yml delete mode 100644 .github/workflows/common.yml delete mode 100644 .github/workflows/ops.yml create mode 100644 bindings/bin/l1staking_deployed.hex delete mode 100644 bindings/bin/submitter_deployed.hex delete mode 100644 bindings/bindings/centralization_cleanup_test.go create mode 100644 bindings/bindings/l1staking.go create mode 100644 bindings/bindings/l1staking_more.go delete mode 100644 bindings/bindings/submitter.go delete mode 100644 bindings/bindings/submitter_more.go delete mode 100644 common/batch/batch_header_zero_test.go delete mode 100644 common/batch/batch_query_test.go delete mode 100644 common/batch/canonical_bootstrap_test.go delete mode 100644 common/batch/config.go delete mode 100644 common/batch/config_test.go delete mode 100644 common/batch/snapshot.go delete mode 100644 contracts/abi/archive/README.md delete mode 100644 contracts/abi/archive/legacy-l1-staking/IL1Staking.json delete mode 100644 contracts/abi/archive/legacy-l1-staking/L1Staking.json delete mode 100644 contracts/abi/archive/manifest.json delete mode 100644 contracts/abi/archive/pre-submitter/Rollup.json create mode 100644 contracts/contracts/Staking.md create mode 100644 contracts/contracts/l1/rollup/BLS.sol delete mode 100644 contracts/contracts/l1/rollup/ISubmitter.sol delete mode 100644 contracts/contracts/l1/rollup/Submitter.sol create mode 100644 contracts/contracts/l1/staking/IL1Staking.sol create mode 100644 contracts/contracts/l1/staking/L1Staking.sol create mode 100644 contracts/contracts/test/L1Staking.t.sol delete mode 100644 contracts/contracts/test/Submitter.t.sol delete mode 100644 contracts/deploy/015-SubmitterInstall.ts create mode 100644 contracts/deploy/018-StakingInit.ts create mode 100644 contracts/deploy/021-StakingRegister.ts delete mode 100644 contracts/deploy/021-SubmitterRegister.ts delete mode 100644 contracts/integration-test/retire-l1-staking.spec.ts delete mode 100644 contracts/integration-test/submitter-deploy.spec.ts delete mode 100644 contracts/ops/legacy-l1-staking-retirement.example.json delete mode 100644 contracts/scripts/clean-generated-abi.js delete mode 100644 contracts/scripts/retire-l1-staking.ts delete mode 100644 contracts/scripts/verify-abi-archive.js delete mode 100644 contracts/storage-layout/archive/Rollup.pre-submitter.json create mode 100644 contracts/tasks/staking_upgrade.ts delete mode 100644 gas-oracle/app/src/abi/pre_submitter/Rollup.json delete mode 100644 gas-oracle/app/src/rollup_compat.rs delete mode 100644 node/core/centralization_cleanup_test.go delete mode 100644 node/derivation/calldata_fixture_test.go delete mode 100644 node/derivation/canonical_commit.go delete mode 100644 node/derivation/canonical_commit_test.go delete mode 100644 node/derivation/testdata/rollup_calldata_fixtures.json delete mode 100644 node/types/abi/pre_submitter_rollup.json delete mode 100644 prover/bin/challenge/src/abi/Submitter.json delete mode 100644 prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json delete mode 100644 prover/bin/challenge/src/abi/pre_submitter/Rollup.json delete mode 100644 prover/bin/challenge/src/proof_signer.rs delete mode 100644 prover/bin/challenge/src/rollup_compat.rs delete mode 100644 prover/bin/shadow-prove/abi/pre_submitter/Rollup.json delete mode 100644 prover/bin/shadow-prove/src/rollup_compat.rs create mode 100644 tx-submitter/event/indexer.go create mode 100644 tx-submitter/event/storage.go create mode 100644 tx-submitter/event/storage_test.go create mode 100644 tx-submitter/mock/event_storage.go create mode 100644 tx-submitter/mock/l1staking.go delete mode 100644 tx-submitter/mock/submitter.go create mode 100644 tx-submitter/params/leveldb_keys.go delete mode 100644 tx-submitter/services/pendingtx_test.go create mode 100644 tx-submitter/services/rotator.go delete mode 100644 tx-submitter/utils/config_test.go diff --git a/.github/workflows/bindings.yml b/.github/workflows/bindings.yml deleted file mode 100644 index eb0b09fd2..000000000 --- a/.github/workflows/bindings.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Bindings - -on: - push: - branches: - - main - paths: - - "build/lint.go" - - "bindings/**" - - "contracts/**" - - ".github/workflows/bindings.yml" - pull_request: - paths: - - "build/lint.go" - - "bindings/**" - - "contracts/**" - - ".github/workflows/bindings.yml" - -permissions: - contents: read - -jobs: - generate-and-test: - name: generate and test - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.x - - name: Install Node - uses: actions/setup-node@v4 - with: - node-version: 18.x - cache: yarn - cache-dependency-path: contracts/yarn.lock - - name: Install pinned Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly-2024-02-23 - - name: Install pinned abigen - run: | - mkdir -p "$RUNNER_TEMP/bin" - GOBIN="$RUNNER_TEMP/bin" go install github.com/ethereum/go-ethereum/cmd/abigen@v1.14.6 - echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" - - name: Regenerate bindings - run: | - yarn --cwd contracts verify:abi-archive - make -C bindings all - yarn --cwd contracts verify:abi-archive - - name: Verify generated files are committed - run: >- - git diff --exit-code -- - bindings/bindings bindings/bin contracts/abi/archive - - name: Run bindings tests - run: make -C bindings test - - name: Lint bindings - run: make -C bindings lint diff --git a/.github/workflows/cherry-pick.yml b/.github/workflows/cherry-pick.yml index e43bc1161..698d82818 100644 --- a/.github/workflows/cherry-pick.yml +++ b/.github/workflows/cherry-pick.yml @@ -15,7 +15,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'release/0.1.x') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v2 with: fetch-depth: 0 - name: Cherry pick into release/0.1.x @@ -31,7 +31,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'release/0.2.x') && github.event.pull_request.merged == true }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v2 with: fetch-depth: 0 - name: Cherry pick into release/0.2.x diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml deleted file mode 100644 index 194bf565f..000000000 --- a/.github/workflows/common.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Common - -on: - push: - branches: - - main - paths: - - "bindings/**" - - "common/**" - - "node/derivation/testdata/rollup_calldata_fixtures.json" - - ".github/workflows/common.yml" - pull_request: - paths: - - "bindings/**" - - "common/**" - - "node/derivation/testdata/rollup_calldata_fixtures.json" - - ".github/workflows/common.yml" - -permissions: - contents: read - -defaults: - run: - working-directory: "common" - -jobs: - test: - name: race tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.x - - name: Run tests with race detector - run: go test -race ./... diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index 40c6b0418..8d3a270d4 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -5,15 +5,14 @@ on: branches: - main paths: - - "build/**" - "contracts/**" - - ".github/workflows/contracts.yml" + - ".github/workflows/contracts.yaml" pull_request: paths: - "build/**" - "contracts/**" - "ops/l2-genesis/**" - - ".github/workflows/contracts.yml" + - ".github/workflows/contracts.yaml" permissions: contents: read @@ -27,21 +26,15 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.x - name: Install Solhint run: npm install -g solhint - - name: Lint Solidity + - name: Lint run: make lint-sol - - name: Lint Go - run: make lint-go test: runs-on: ubuntu-latest @@ -49,9 +42,9 @@ jobs: FORCE_COLOR: 1 GAS: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v3 with: node-version: 18.x - name: Install Go diff --git a/.github/workflows/deployer.yml b/.github/workflows/deployer.yml index 50e976db4..184680c6b 100644 --- a/.github/workflows/deployer.yml +++ b/.github/workflows/deployer.yml @@ -5,16 +5,15 @@ on: branches: - main paths: - - "build/**" - "ops/l2-genesis/**" - - ".github/workflows/deployer.yml" + - ".github/workflows/deployer.yaml" pull_request: paths: - "build/**" - "bindings/**" - "node/**" - "ops/l2-genesis/**" - - ".github/workflows/deployer.yml" + - ".github/workflows/deployer.yaml" permissions: contents: read @@ -28,7 +27,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: @@ -40,7 +39,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/.github/workflows/gas-oracle.yml b/.github/workflows/gas-oracle.yml index 51149f7aa..ab1e3ea80 100644 --- a/.github/workflows/gas-oracle.yml +++ b/.github/workflows/gas-oracle.yml @@ -6,15 +6,11 @@ on: - main paths: - "gas-oracle/**" - - "node/derivation/testdata/rollup_calldata_fixtures.json" - - "ops/docker/Dockerfile.oracle" - - ".github/workflows/gas-oracle.yml" + - ".github/workflows/gas-oracle.yaml" pull_request: paths: - "gas-oracle/**" - - "node/derivation/testdata/rollup_calldata_fixtures.json" - - "ops/docker/Dockerfile.oracle" - - ".github/workflows/gas-oracle.yml" + - ".github/workflows/gas-oracle.yaml" permissions: contents: read @@ -27,20 +23,8 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Install pinned Rust toolchain - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.91.0 - components: rustfmt, clippy + - uses: actions/checkout@v3 - name: Run build run: make build - name: Run tests run: make test - - name: Check formatting - run: make fmt - - name: Run clippy - run: make clippy - - name: Build oracle container - working-directory: ${{ github.workspace }} - run: docker build -f ops/docker/Dockerfile.oracle . diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 559606c94..8b9773d3e 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -5,16 +5,15 @@ on: branches: - main paths: - - "build/**" - "node/**" - - ".github/workflows/node.yml" + - ".github/workflows/node.yaml" pull_request: paths: - "build/**" - "bindings/**" - "node/**" - "ops/l2-genesis/**" - - ".github/workflows/node.yml" + - ".github/workflows/node.yaml" permissions: contents: read @@ -28,7 +27,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: @@ -40,7 +39,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/.github/workflows/ops.yml b/.github/workflows/ops.yml deleted file mode 100644 index 00037a109..000000000 --- a/.github/workflows/ops.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Ops - -on: - push: - branches: - - main - paths: - - "build/**" - - "node/ops-morph/**" - - "ops/devnet-morph/**" - - "ops/docker/**" - - "ops/tools/**" - - ".github/workflows/ops.yml" - pull_request: - paths: - - "build/**" - - "node/ops-morph/**" - - "ops/devnet-morph/**" - - "ops/docker/**" - - "ops/tools/**" - - ".github/workflows/ops.yml" - -permissions: - contents: read - -jobs: - go-lint: - name: ops tools lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.x - - name: Lint ops tools - run: make -C ops/tools lint - - devnet-config: - name: devnet config tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Run deterministic devnet tests - run: python3 -m unittest discover -s ops/devnet-morph/tests -v - - name: Validate Compose configuration - working-directory: ops/docker - run: >- - docker compose - -f docker-compose-devnet.yml - -f docker-compose-cluster.yml - config --quiet diff --git a/.github/workflows/prover.yml b/.github/workflows/prover.yml index bdc222c9f..8e611539a 100644 --- a/.github/workflows/prover.yml +++ b/.github/workflows/prover.yml @@ -5,14 +5,12 @@ on: branches: - main paths: - - "node/derivation/testdata/rollup_calldata_fixtures.json" - "prover/**" - - ".github/workflows/prover.yml" + - ".github/workflows/prover.yaml" pull_request: paths: - - "node/derivation/testdata/rollup_calldata_fixtures.json" - "prover/**" - - ".github/workflows/prover.yml" + - ".github/workflows/prover.yaml" permissions: contents: read @@ -28,32 +26,15 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: nightly-2024-07-07 - components: rustfmt - - name: Check shadow-prove formatting - run: cargo +nightly-2024-07-07 fmt --package shadow-proving --check - - name: Check challenge formatting - run: >- - cargo +nightly-2024-07-07 fmt - --manifest-path bin/challenge/Cargo.toml - --check + - uses: dtolnay/rust-toolchain@stable + - run: rustup component add rustfmt --toolchain nightly-2024-07-07 + - run: cargo fmt --all --check build: name: build runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 30 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.91.0 - - name: Build shadow-prove - run: make build-shadow-prove - - name: Test shadow-prove - run: cargo test --manifest-path bin/shadow-prove/Cargo.toml - - name: Build challenge - run: make build-challenge - - name: Test challenge - run: cargo test --manifest-path bin/challenge/Cargo.toml + - uses: dtolnay/rust-toolchain@stable + - run: make build-shadow-prove && make build-shadow-prove diff --git a/.github/workflows/tx-submitter.yml b/.github/workflows/tx-submitter.yml index 171e9b56b..ae8fec5b3 100644 --- a/.github/workflows/tx-submitter.yml +++ b/.github/workflows/tx-submitter.yml @@ -5,20 +5,16 @@ on: branches: - main paths: - - "build/**" - - "bindings/**" - - "common/**" - "tx-submitter/**" - - ".github/workflows/tx-submitter.yml" + - ".github/workflows/tx-submitter.yaml" pull_request: paths: - "build/**" - "bindings/**" - - "common/**" - "node/**" - "ops/l2-genesis/**" - "tx-submitter/**" - - ".github/workflows/tx-submitter.yml" + - ".github/workflows/tx-submitter.yaml" permissions: contents: read @@ -32,7 +28,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: @@ -44,7 +40,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Install Go uses: actions/setup-go@v5 with: diff --git a/bindings/Makefile b/bindings/Makefile index 616ebf372..a98e10d37 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -5,7 +5,7 @@ pkg := bindings all: version mkdir bindings more bindings: \ - submitter-bindings \ + l1-staking-bindings \ l1-cross-domain-messenger-bindings \ l1-standard-erc20-gateway-bindings \ l1-eth-gateway-bindings \ @@ -65,9 +65,9 @@ compile-forge: ./compile.sh forge ## L1 -# Submitter -submitter-bindings: compile - ./gen_bindings.sh contracts/l1/rollup/Submitter.sol:Submitter $(pkg) +# Staking +l1-staking-bindings: compile + ./gen_bindings.sh contracts/l1/staking/L1Staking.sol:L1Staking $(pkg) # CrossDomainMessenger l1-cross-domain-messenger-bindings: compile @@ -194,7 +194,7 @@ more: compile-forge go run ./gen/main.go \ -artifacts ../contracts/artifacts \ -out ./bindings \ - -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,Submitter,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ + -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,L1Staking,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ -package bindings mkdir: @@ -211,3 +211,4 @@ test: lint: GOBIN=$(PWD)/build/bin go run ../build/lint.go .PHONY: lint + diff --git a/bindings/bin/l1staking_deployed.hex b/bindings/bin/l1staking_deployed.hex new file mode 100644 index 000000000..401476f33 --- /dev/null +++ b/bindings/bin/l1staking_deployed.hex @@ -0,0 +1 @@ +0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bin/rollup_deployed.hex b/bindings/bin/rollup_deployed.hex index 502f165cb..68a52ca9c 100644 --- a/bindings/bin/rollup_deployed.hex +++ b/bindings/bin/rollup_deployed.hex @@ -1 +1 @@ -0x608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610b2c578063f2fde38b14610b4b578063f8fa010f14610b6a578063fb1e8b0414610b89575f80fd5b8063d279c19114610ac4578063d8dc99d214610ae3578063de8b303514610af8578063dff7827e14610b17575f80fd5b8063c5553892116100d8578063c555389214610a5e578063cd4edc6914610a7d578063ce5db8d614610a90578063cf9a674514610aa5575f80fd5b8063b3e0a50914610a01578063b8d0a1b014610a20578063bedb86fb14610a3f575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d14610983578063b31a77d3146109ae578063b3484425146109c3578063b35dac4e146109e2575f80fd5b8063a415d8dc14610921578063a479265d1461094f578063a4f209b014610964575f80fd5b80638f1d3776116101a35780638f1d377614610802578063910129d4146108b257806397fc007c146108e3578063a3c9e94c14610902575f80fd5b806388b1ea09146107a15780638da5cb5b146107ba5780638ef622a8146107d7575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107245780636c578c1d1461074f578063715018a61461076e578063728cdbca14610782575f80fd5b80635f77cf1d1461069a57806361267290146106e657806367caa37a14610705575f80fd5b806341f756da1161027957806341f756da146105df57806357e0af6c146105f25780635c975abb146106115780635ef7a94a14610628575f80fd5b80632b7ac3f3146105745780633b70c18a146105ab5780633e001b66146105ca575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e36600461529d565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046152ca565b610b9e565b005b348015610406575f80fd5b506103f9610415366004615328565b610c70565b348015610425575f80fd5b506103a261043436600461529d565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004615370565b610fb5565b34801561047b575f80fd5b506103f961048a3660046153bf565b6114db565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be36600461529d565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee36600461529d565b61189a565b3480156104fe575f80fd5b506103cc61050d36600461529d565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc61053836600461529d565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc61056336600461529d565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c54610593906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105b6575f80fd5b50609b54610593906001600160a01b031681565b3480156105d5575f80fd5b506103cc60aa5481565b6103f96105ed36600461544d565b6118c8565b3480156105fd575f80fd5b506103f961060c36600461529d565b611b66565b34801561061c575f80fd5b5060655460ff166103a2565b348015610633575f80fd5b5061067161064236600461529d565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106a5575f80fd5b506106cd7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b3480156106f1575f80fd5b506103f961070036600461529d565b611c11565b348015610710575f80fd5b506103f961071f36600461544d565b611dee565b34801561072f575f80fd5b506103cc61073e36600461529d565b60ab6020525f908152604090205481565b34801561075a575f80fd5b506103f96107693660046152ca565b612139565b348015610779575f80fd5b506103f96121f6565b34801561078d575f80fd5b506103f961079c366004615487565b612209565b3480156107ac575f80fd5b5060a6546103a29060ff1681565b3480156107c5575f80fd5b506033546001600160a01b0316610593565b3480156107e2575f80fd5b506103cc6107f13660046152ca565b60ae6020525f908152604090205481565b34801561080d575f80fd5b5061086e61081c36600461529d565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108bd575f80fd5b506103a26108cc36600461529d565b5f90815260a4602052604090206003015460ff1690565b3480156108ee575f80fd5b506103f96108fd3660046152ca565b612512565b34801561090d575f80fd5b50609754610593906001600160a01b031681565b34801561092c575f80fd5b506103a261093b3660046152ca565b609f6020525f908152604090205460ff1681565b34801561095a575f80fd5b506103cc60995481565b34801561096f575f80fd5b506103f961097e36600461529d565b6125f5565b34801561098e575f80fd5b506103cc61099d3660046152ca565b60a56020525f908152604090205481565b3480156109b9575f80fd5b506103cc60a85481565b3480156109ce575f80fd5b506103f96109dd3660046154e2565b6126a5565b3480156109ed575f80fd5b506103f96109fc3660046152ca565b6129b2565b348015610a0c575f80fd5b506103f9610a1b366004615370565b612a0b565b348015610a2b575f80fd5b506103f9610a3a3660046154e2565b612d9c565b348015610a4a575f80fd5b506103f9610a59366004615556565b612e25565b348015610a69575f80fd5b506103f9610a7836600461529d565b612f63565b6103f9610a8b366004615588565b613006565b348015610a9b575f80fd5b506103cc60985481565b348015610ab0575f80fd5b506103f9610abf36600461529d565b613598565b348015610acf575f80fd5b506103f9610ade3660046152ca565b61370f565b348015610aee575f80fd5b506103cc60ac5481565b348015610b03575f80fd5b506103a2610b1236600461529d565b6137ce565b348015610b22575f80fd5b506103cc609a5481565b348015610b37575f80fd5b506103f9610b4636600461529d565b613818565b348015610b56575f80fd5b506103f9610b653660046152ca565b6138bb565b348015610b75575f80fd5b506103f9610b843660046152ca565b613948565b348015610b94575f80fd5b506103cc60a95481565b610ba6613e4d565b6001600160a01b0381165f908152609f602052604090205460ff1615610c135760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c78613e4d565b5f8111610cc75760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c0a565b5f80610cd38585613ea7565b915091505f610ce6836001015160c01c90565b5f81815260a160205260409020549091508214610d455760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f60a181610d5387856155dd565b81526020019081526020015f205414610dd35760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b609d548111610e4a5760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b610e556001826155f0565b609e555b8315610fad57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610e9381613f4f565b5f81815260a16020526040812055610eaa816137ce565b15610f05575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ef59084906155dd565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f65575060a85481145b15610f6f575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e59575b505050505050565b60a854156110055760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b61100d614002565b5f806110198484613ea7565b915091505f61102c836001015160c01c90565b5f81815260a16020526040902054909150821461108b5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6110948161189a565b6110e05760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b6110e9816137ce565b156111365760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a4602052604090206003015460ff16156111975760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c0a565b5f81815260a260205260409020600101544210156111f75760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c0a565b605983015160a05f61120a6001856155f0565b81526020019081526020015f2054146112655760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f81815260a06020526040902054156112c05760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c0a565b80609d54600101146113145760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b609d819055600160a35f611329866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561137861136b846011015160c01c90565b600985015160c01c614055565b61138181613f4f565b60a25f61138f6001846155f0565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113eb90846155f0565b81526020019081526020015f205f905560ad5f60018361140b91906155f0565b81526020019081526020015f205f905560a45f60018361142b91906155f0565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d6114b7866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a8541561152b5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611533614002565b60ac54609e545f90815260a260205260408120549091429161155591906155dd565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d19190615603565b6115db91906155dd565b109050811580156115e95750805b15611650575f6115ff6080890160608a0161561a565b61ffff16116116505760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b81806116595750805b6116a55760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c0a565b5f6116bb6116b660208a018a61563b565b613ea7565b5090505f6116cd826001015160c01c90565b6116d89060016155dd565b5f81815260ad60205260408120549192509015611778575f49156117645760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c0a565b505f81815260ad6020526040902054611793565b61179061178860208c018c61569c565b60ff16614112565b90505b61179e8a5f8361424d565b5f806117aa8b8b613ea7565b915091505f6117bd836001015160c01c90565b905080609e54146118105760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461186c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f81815260a2602052604090204260019091015561188b838b8b6147af565b50505050505050505050505050565b5f81815260a26020526040812054158015906118c257505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611934573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195891906156bc565b6119a45760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a854156119f45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6119fc614002565b5f49611a4a5760405162461bcd60e51b815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aae573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad29190615603565b611adc91906155dd565b1015611b44575f611af3608083016060840161561a565b61ffff1611611b445760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b5f611b55611788602084018461569c565b9050611b6282338361424d565b5050565b611b6e613e4d565b5f81118015611b7f57506099548114155b611bcb5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c0a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c3157505f5460ff8083169116105b611ca35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055611cbe613e4d565b5f5460ff1660ff16600214611d155760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c0a565b81611d885760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c0a565b609e545f90815260ab6020526040902054611db157609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7e91906156bc565b611eca5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a85415611f1a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611f22614002565b5f4915611f715760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c0a565b5f611f826116b6602084018461563b565b5090505f611f94826001015160c01c90565b611f9f9060016155dd565b5f81815260ad60205260409020549091506120225760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015612086573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120aa9190615603565b6120b491906155dd565b101561211c575f6120cb608085016060860161561a565b61ffff161161211c5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b61213483335f84815260ad602052604090205461424d565b505050565b612141613e4d565b6001600160a01b0381165f908152609f602052604090205460ff166121a85760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c0a565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c65565b6121fe613e4d565b6122075f614962565b565b5f54610100900460ff161580801561222757505f54600160ff909116105b806122405750303b15801561224057505f5460ff166001145b6122b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805460ff1916600117905580156122d3575f805461ff0019166101001790555b6001600160a01b03861615806122f057506001600160a01b038516155b15612327576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871661237d5760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c0a565b6123856149cb565b61238d614a4f565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612509575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61251a613e4d565b6001600160a01b038116158015906125405750609c546001600160a01b03828116911614155b61258c5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c0a565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6125fd613e4d565b5f8111801561260d575060648111155b801561261b575060a9548114155b6126675760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c0a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c05565b60a854156126f55760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6126fd614002565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612769573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278d91906156bc565b6127d95760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b5f806127e58686613ea7565b915091505f6127f8836001015160c01c90565b5f81815260a1602052604090205490915082146128575760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b612860816137ce565b6128ac5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916128e8916155dd565b11612967575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526129629183916001600160a01b031690614ad3565b612509565b6129728386866147af565b61250981336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614c32565b6129ba613e4d565b60aa80545f9091556129cc8282614cfe565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c05565b612a13613e4d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612a8a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c0a565b5f80612a968484613ea7565b915091505f612aa9836001015160c01c90565b90508015612af95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c0a565b5f612b05846079015190565b905080612b545760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c0a565b600984015160c01c15612ba95760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c0a565b5f612bb5856019015190565b03612c025760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c0a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c2e856039015190565b14612c7b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c0a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612da88686613ea7565b915091505f612dbb836001015160c01c90565b5f81815260a160205260409020549091508214612e1a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6125098386866147af565b612e2d613e4d565b8015612f3157612e3b614da3565b60a65460ff1615612ef05760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612e8f9084906155dd565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f39614dfd565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f13565b50565b612f6b613e4d565b5f81118015612f7c575060ac548114155b612fc85760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c0a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c05565b335f908152609f602052604090205460ff166130645760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c0a565b60a854156130b45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6130bc614002565b60a65460ff161561310f5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c0a565b8167ffffffffffffffff16609d541061316a5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a1602052604090205481146131d15760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6131e48267ffffffffffffffff1661189a565b6132305760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132ab5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a26020526040902060010154421061333b5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c0a565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190615603565b3410156133fe5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161351691815260200190565b60405180910390a35f609d54600161352e91906155dd565b90505b609e548111613586578267ffffffffffffffff168114613574576099545f82815260a260205260408120600101805490919061356e9084906155dd565b90915550505b8061357e816156d7565b915050613531565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135b857505f5460ff8083169116105b61362a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055613645613e4d565b815f036136945760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c0a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b335f90815260a560205260408120549081900361376e5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c0a565b335f90815260a560205260408120556137878282614cfe565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137c291815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118c25750505f90815260a46020526040902060030154610100900460ff161590565b613820613e4d565b5f8111801561383157506098548114155b61387d5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c0a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c05565b6138c3613e4d565b6001600160a01b03811661393f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c0a565b612f6081614962565b5f54600490610100900460ff1615801561396857505f5460ff8083169116105b6139da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff8316176101001790556139f5613e4d565b6001600160a01b03821615801590613a1657505f826001600160a01b03163b115b613a625760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c0a565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90613ac6908490614e36565b905060a081901c15613b1a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610c0a565b6040515f602482018190528291613bab908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052614e36565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f90613c12908790614e36565b90506001600160a01b0383163014613c6c5760405162461bcd60e51b815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610c0a565b81158015613c7957505f81115b613cc55760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610c0a565b609d54609e5414613d185760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c0a565b60a85415613d685760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560975490516001600160a01b03898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861617905550505f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6033546001600160a01b031633146122075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c0a565b5f805f613eb48585614ebf565b90505f8160ff165f03613ed557613ecb8686614f2f565b9094509050613f41565b8160ff1660011480613eea57508160ff166002145b15613ef957613ecb8686614f98565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c0a565b808420925050509250929050565b5f81815260a260205260409020600301546001600160a01b031680613f72575050565b6001600160a01b0381165f90815260ae602052604090205480613fd75760405162461bcd60e51b815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610c0a565b613fe26001826155f0565b6001600160a01b039092165f90815260ae60205260409020919091555050565b60655460ff16156122075760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c0a565b805f03614060575050565b8082035f5b8281101561410c5761010081840381111561407f57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b1580156140e2575f80fd5b505af11580156140f4573d5f803e3d5ffd5b50505050610100830192505061010081019050614065565b50505050565b5f816002036141a1575f6040515f5b80498061412e575061413d565b60208202830152600101614121565b60208102808320920160405290925090508061419b5760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c0a565b50919050565b600149156142175760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c0a565b5f4915614225575f496118c2565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261425c602085018561569c565b60ff1611156142ad5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c0a565b60808301356142fe5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c0a565b60a083013561434f5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c0a565b5f806143616116b6602087018761563b565b915091505f614374836001015160c01c90565b90505f60a1816143858460016155dd565b81526020019081526020015f2054146143e05760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c0a565b609e5481146144315760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461448d5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c0a565b5f81815260ab60205260409020546080870135146144ed5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f6144fc846011015160c01c90565b90505f61452861451260608a0160408b0161570e565b61452260808b0160608c0161561a565b84614feb565b905061453a6080890160608a0161561a565b60019384019361ffff91909116929092019160f99061455c60208b018b61569c565b60ff161061456957506101015b60408051828101909152955061458e8661458660208c018c61569c565b60ff1661502f565b60c084901b60018701526145bc866145ac60808c0160608d0161561a565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161460c60208b018b61569c565b60ff161061463e5761463e8661462860608c0160408d0161570e565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156146a75760a7545f90815260a46020526040902060020154609954429161469a916155dd565b6146a491906155f0565b90505b604051806080016040528042815260200182609854426146c791906155dd565b6146d191906155dd565b81526020016146e660608d0160408e0161570e565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561476589615036565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b806147fc5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c0a565b5f61480b846001015160c01c90565b90505f614819856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614848876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a84861490a885160f81c90565b858888866040518663ffffffff1660e01b815260040161492e959493929190615727565b5f6040518083038186803b158015614944575f80fd5b505afa158015614956573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16614a475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b612207615075565b5f54610100900460ff16614acb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6122076150fd565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614b5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b7e9190615603565b5f86815260a46020526040902060010154909150614b9d9082906155dd565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a590915281208054909190614bdc9084906155dd565b9091555050604051614bef90849061578a565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614c5690846157b6565b614c6091906157cd565b9050614c6c81836155f0565b60aa5f828254614c7c91906155dd565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614ca89084906155dd565b9091555050604051614cbb90849061578a565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611b62575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614d4d576040519150601f19603f3d011682016040523d82523d5f602084013e614d52565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c0a565b614dab614002565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614de03390565b6040516001600160a01b03909116815260200160405180910390a1565b614e05615182565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614de0565b5f805f805f855160208701885afa91503d905060208114821615614e5e5760205f803e5f5192505b818015614e6b5750806020145b614eb75760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610c0a565b505092915050565b5f81614f0d5760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c0a565b82825f818110614f1f57614f1f615805565b919091013560f81c949350505050565b5f8160f9811015614f825760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c0a565b6040519150808483378082016040529250929050565b5f816101018114614f825760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c0a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f9181016150208161ffff8716866151d4565b82900390912095945050505050565b8082535050565b6001600160a01b03811615612f60576001600160a01b0381165f90815260ae6020526040812080546001929061506d9084906155dd565b909155505050565b5f54610100900460ff166150f15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6065805460ff19169055565b5f54610100900460ff166151795760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b61220733614962565b60655460ff166122075760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c0a565b5f825f036151e3575082615296565b609b546001600160a01b03165f5b84811015615290576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015615257573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061527b9190615603565b875250602090950194600193840193016151f1565b50849150505b9392505050565b5f602082840312156152ad575f80fd5b5035919050565b80356001600160a01b0381168114614248575f80fd5b5f602082840312156152da575f80fd5b615296826152b4565b5f8083601f8401126152f3575f80fd5b50813567ffffffffffffffff81111561530a575f80fd5b602083019150836020828501011115615321575f80fd5b9250929050565b5f805f6040848603121561533a575f80fd5b833567ffffffffffffffff811115615350575f80fd5b61535c868287016152e3565b909790965060209590950135949350505050565b5f8060208385031215615381575f80fd5b823567ffffffffffffffff811115615397575f80fd5b6153a3858286016152e3565b90969095509350505050565b5f60e0828403121561419b575f80fd5b5f805f805f606086880312156153d3575f80fd5b853567ffffffffffffffff808211156153ea575f80fd5b6153f689838a016153af565b9650602088013591508082111561540b575f80fd5b61541789838a016152e3565b9096509450604088013591508082111561542f575f80fd5b5061543c888289016152e3565b969995985093965092949392505050565b5f6020828403121561545d575f80fd5b813567ffffffffffffffff811115615473575f80fd5b61547f848285016153af565b949350505050565b5f805f805f8060c0878903121561549c575f80fd5b6154a5876152b4565b95506154b3602088016152b4565b94506154c1604088016152b4565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156154f5575f80fd5b843567ffffffffffffffff8082111561550c575f80fd5b615518888389016152e3565b90965094506020870135915080821115615530575f80fd5b5061553d878288016152e3565b95989497509550505050565b8015158114612f60575f80fd5b5f60208284031215615566575f80fd5b813561529681615549565b803567ffffffffffffffff81168114614248575f80fd5b5f8060408385031215615599575f80fd5b6155a283615571565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118c2576118c26155b0565b818103818111156118c2576118c26155b0565b5f60208284031215615613575f80fd5b5051919050565b5f6020828403121561562a575f80fd5b813561ffff81168114615296575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261566e575f80fd5b83018035915067ffffffffffffffff821115615688575f80fd5b602001915036819003821315615321575f80fd5b5f602082840312156156ac575f80fd5b813560ff81168114615296575f80fd5b5f602082840312156156cc575f80fd5b815161529681615549565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615707576157076155b0565b5060010190565b5f6020828403121561571e575f80fd5b61529682615571565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156157a9576020818601810151858301520161578f565b505f920191825250919050565b80820281158282048414176118c2576118c26155b0565b5f82615800577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a +0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a diff --git a/bindings/bin/submitter_deployed.hex b/bindings/bin/submitter_deployed.hex deleted file mode 100644 index b62e9ebe8..000000000 --- a/bindings/bin/submitter_deployed.hex +++ /dev/null @@ -1 +0,0 @@ -0x60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd111461044a578063d13f90b414610469578063ec5ffac214610488578063f2fde38b1461049d575f80fd5b8063bfa02ba9146103ed578063c36f41e21461040c578063c96be4cb1461042b575f80fd5b8063ab8c53dc116100b7578063ab8c53dc1461037c578063b2dd5c0714610391578063bbfefd38146103bf575f80fd5b80639f8a13d71461030f578063a3066aab1461033e578063a4f209b01461035d575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac366004611cca565b6104bc565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f5366004611cea565b6105b4565b348015610205575f80fd5b506101b1610214366004611cea565b61065a565b6101b1610700565b34801561022c575f80fd5b506101c861023b366004611cca565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c8610266366004611cca565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b1610291366004611cca565b61086e565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c5366004611cca565b610a06565b3480156102d5575f80fd5b506101b1610b45565b3480156102e9575f80fd5b506033546001600160a01b03165b6040516001600160a01b0390911681526020016101d2565b34801561031a575f80fd5b5061032e610329366004611cca565b610b56565b60405190151581526020016101d2565b348015610349575f80fd5b506101b1610358366004611cca565b610bc0565b348015610368575f80fd5b506101b1610377366004611cea565b610ce5565b348015610387575f80fd5b506101c8609b5481565b34801561039c575f80fd5b5061032e6103ab366004611cca565b609c6020525f908152604090205460ff1681565b3480156103ca575f80fd5b5061032e6103d9366004611cca565b609e6020525f908152604090205460ff1681565b3480156103f8575f80fd5b506097546102f7906001600160a01b031681565b348015610417575f80fd5b506101b1610426366004611cca565b610d98565b348015610436575f80fd5b506101c8610445366004611cca565b610ef8565b348015610455575f80fd5b506101b1610464366004611cca565b611064565b348015610474575f80fd5b506101b1610483366004611d01565b611176565b348015610493575f80fd5b506101c860985481565b3480156104a8575f80fd5b506101b16104b7366004611cca565b61158a565b6104c4611617565b6001600160a01b038116158015906104f457506001600160a01b0381165f908152609c602052604090205460ff16155b801561051857506001600160a01b0381165f908152609e602052604090205460ff16155b6105695760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105bc611617565b5f811180156105cd57506098548114155b6106195760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610662611617565b5f8111801561067357506099548114155b6106bf5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610708611671565b335f818152609c602052604090205460ff16801561073e57506001600160a01b0381165f908152609e602052604090205460ff16155b61078a5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609d60205260408120546107ad903490611d77565b90505f341180156107c057506098548110155b61080c5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610560565b6001600160a01b0382165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061086c6001606555565b565b610876611671565b336001600160a01b0382166108cd5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609c602052604090205460ff16801561090c57506001600160a01b0381165f908152609e602052604090205460ff16155b801561092e57506001600160a01b0381165f908152609d602052604090205415155b61097a5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610560565b6001600160a01b038181165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a36109f881836116d1565b50610a036001606555565b50565b610a0e611671565b336001600160a01b038216610a655760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609f602052604090205480610aca5760405162461bcd60e51b815260206004820152600960248201527f6e6f2063726564697400000000000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0382165f908152609f6020526040812055610aec83826116ed565b826001600160a01b0316826001600160a01b03167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610b3191815260200190565b60405180910390a35050610a036001606555565b610b4d611617565b61086c5f61179c565b6001600160a01b0381165f908152609c602052604081205460ff168015610b9557506001600160a01b0382165f908152609e602052604090205460ff16155b8015610bba57506098546001600160a01b0383165f908152609d602052604090205410155b92915050565b610bc8611671565b336001600160a01b038216610c1f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609e602052604090205460ff16610c865760405162461bcd60e51b815260206004820152600b60248201527f6e6f742065786974696e670000000000000000000000000000000000000000006044820152606401610560565b610c8f81611805565b610cdb5760405162461bcd60e51b815260206004820152601760248201527f70656e64696e67206261746368206c696162696c6974790000000000000000006044820152606401610560565b6109f881836118f0565b610ced611617565b5f81118015610cfd575060648111155b8015610d0b5750609a548114155b610d575760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610da0611617565b610da8611671565b6001600160a01b0381165f908152609c602052604090205460ff168015610de757506001600160a01b0381165f908152609e602052604090205460ff16155b610e335760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f818152609c60209081526040808320805460ff19908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a26001600160a01b0381165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b3291610edc91815260200190565b60405180910390a3610eee81826116d1565b610a036001606555565b6097545f906001600160a01b0316336001600160a01b031614610f5d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610560565b610f65611671565b6001600160a01b038216610f7a57505f611055565b6001600160a01b0382165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216600117909155609a54606490610fce9083611d8a565b610fd89190611da1565b9150610fe48282611dd9565b609b5f828254610ff49190611d77565b909155505060975461100f906001600160a01b0316836116ed565b60408051828152602081018490526001600160a01b038516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61105f6001606555565b919050565b61106c611617565b611074611671565b6001600160a01b0381166110ca5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b609b548061111a5760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610560565b5f609b5561112882826116ed565b816001600160a01b03167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161116391815260200190565b60405180910390a250610a036001606555565b5f54610100900460ff161580801561119457505f54600160ff909116105b806111ad5750303b1580156111ad57505f5460ff166001145b61121f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610560565b5f805460ff19166001179055801561125d575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0386166112b35760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610560565b6001600160a01b038516158015906112d457505f856001600160a01b03163b115b6113205760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610560565b5f841161136f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b5f83116113be5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b5f821180156113ce575060648211155b61141a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b611422611aab565b61142a611b2f565b6114338661179c565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611582575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611592611617565b6001600160a01b03811661160e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610560565b610a038161179c565b6033546001600160a01b0316331461086c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610560565b6002606554036116c35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610560565b6002606555565b6001606555565b6116da82611805565b156116e9576116e982826118f0565b5050565b805f036116f8575050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611741576040519150601f19603f3d011682016040523d82523d5f602084013e611746565b606091505b50509050806117975760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610560565b505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6040516001600160a01b03821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a80000000000000000000000000000000000000000000000000000000017815260975482519293506001600160a01b0316915f9182918291829182918761c350fa92503d9150602082148316156118ce5760205f803e505f515b8280156118db5750816020145b80156118e5575080155b979650505050505050565b6001600160a01b0382165f908152609d60209081526040808320805490849055609e9092528220805460ff191690559081900361197957816001600160a01b0316836001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f60405161196c91815260200190565b60405180910390a3505050565b5f826001600160a01b03168261c350906040515f60405180830381858888f193505050503d805f81146119c7576040519150601f19603f3d011682016040523d82523d5f602084013e6119cc565b606091505b505090508015611a2857826001600160a01b0316846001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f4684604051611a1b91815260200190565b60405180910390a3611aa5565b6001600160a01b0384165f908152609f602052604081208054849290611a4f908490611d77565b90915550506001600160a01b0384165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff16611b275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611bb3565b5f54610100900460ff16611bab5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611c38565b5f54610100900460ff16611c2f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c3361179c565b5f54610100900460ff166116ca5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b80356001600160a01b038116811461105f575f80fd5b5f60208284031215611cda575f80fd5b611ce382611cb4565b9392505050565b5f60208284031215611cfa575f80fd5b5035919050565b5f805f805f60a08688031215611d15575f80fd5b611d1e86611cb4565b9450611d2c60208701611cb4565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610bba57610bba611d4a565b8082028115828204841417610bba57610bba611d4a565b5f82611dd4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610bba57610bba611d4a56fea164736f6c6343000818000a diff --git a/bindings/bindings/centralization_cleanup_test.go b/bindings/bindings/centralization_cleanup_test.go deleted file mode 100644 index 1650aef50..000000000 --- a/bindings/bindings/centralization_cleanup_test.go +++ /dev/null @@ -1,237 +0,0 @@ -package bindings - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "os" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/morph-l2/go-ethereum/accounts/abi" -) - -const ( - oldCommitBatchSelector = "428868b5" - oldCommitStateSelector = "1e8825be" - oldCommitBatchWithProofSelector = "4e8f1d67" - newCommitBatchSelector = "41f756da" - newCommitStateSelector = "67caa37a" - newCommitBatchWithProofSelector = "1544ba3a" -) - -type calldataCorpus struct { - SchemaVersion int `json:"schemaVersion"` - Fixtures []struct { - Name string `json:"name"` - Epoch string `json:"epoch"` - Selector string `json:"selector"` - Data string `json:"data"` - } `json:"fixtures"` -} - -func repositoryRoot(t *testing.T) string { - t.Helper() - _, filename, _, ok := runtime.Caller(0) - if !ok { - t.Fatal("resolve test source path") - } - return filepath.Clean(filepath.Join(filepath.Dir(filename), "..", "..")) -} - -func readABI(t *testing.T, path string) abi.ABI { - t.Helper() - raw, err := os.Open(path) - if err != nil { - t.Fatalf("open ABI %s: %v", path, err) - } - defer raw.Close() - parsed, err := abi.JSON(raw) - if err != nil { - t.Fatalf("parse ABI %s: %v", path, err) - } - return parsed -} - -func methodSelector(t *testing.T, parsed abi.ABI, name string) string { - t.Helper() - method, ok := parsed.Methods[name] - if !ok { - t.Fatalf("ABI is missing method %s", name) - } - return hex.EncodeToString(method.ID) -} - -func TestGeneratedRollupBindingShape(t *testing.T) { - current, err := RollupMetaData.GetAbi() - if err != nil { - t.Fatalf("parse generated Rollup ABI: %v", err) - } - if current == nil { - t.Fatal("generated Rollup ABI is nil") - } - if strings.Contains(RollupMetaData.ABI, "BatchSignatureInput") { - t.Fatal("generated Rollup binding still contains BatchSignatureInput") - } - - expected := map[string]struct { - selector string - inputs int - }{ - "commitBatch": {newCommitBatchSelector, 1}, - "commitState": {newCommitStateSelector, 1}, - "commitBatchWithProof": {newCommitBatchWithProofSelector, 3}, - } - for name, want := range expected { - method, ok := current.Methods[name] - if !ok { - t.Fatalf("generated Rollup ABI is missing %s", name) - } - if got := hex.EncodeToString(method.ID); got != want.selector { - t.Fatalf("%s selector = %s, want %s", name, got, want.selector) - } - if got := len(method.Inputs); got != want.inputs { - t.Fatalf("%s input count = %d, want %d", name, got, want.inputs) - } - } - - batchDataStore, ok := current.Methods["batchDataStore"] - if !ok { - t.Fatal("generated Rollup ABI is missing batchDataStore") - } - if len(batchDataStore.Outputs) != 4 || batchDataStore.Outputs[3].Type.String() != "address" { - t.Fatalf("batchDataStore output shape = %v, want fourth output address", batchDataStore.Outputs) - } - if _, ok := current.Methods["pendingBatchCount"]; !ok { - t.Fatal("generated Rollup ABI is missing pendingBatchCount") - } -} - -func TestGeneratedSubmitterBindingShape(t *testing.T) { - current, err := SubmitterMetaData.GetAbi() - if err != nil { - t.Fatalf("parse generated Submitter ABI: %v", err) - } - if current == nil { - t.Fatal("generated Submitter ABI is nil") - } - for _, name := range []string{ - "addSubmitter", - "claimCredit", - "claimWithdrawal", - "initialize", - "isActive", - "removeSubmitter", - "slash", - "stake", - "withdraw", - } { - if _, ok := current.Methods[name]; !ok { - t.Fatalf("generated Submitter ABI is missing %s", name) - } - } - active := current.Methods["isActive"] - if len(active.Inputs) != 1 || len(active.Outputs) != 1 || active.Outputs[0].Type.String() != "bool" { - t.Fatalf("isActive ABI shape changed: inputs=%v outputs=%v", active.Inputs, active.Outputs) - } -} - -func TestPreSubmitterAndCurrentSelectorsRemainDistinct(t *testing.T) { - root := repositoryRoot(t) - preSubmitter := readABI(t, filepath.Join( - root, - "contracts", - "abi", - "archive", - "pre-submitter", - "Rollup.json", - )) - current, err := RollupMetaData.GetAbi() - if err != nil || current == nil { - t.Fatalf("parse generated Rollup ABI: %v", err) - } - - tests := []struct { - name string - oldSelector string - newSelector string - oldInputCount int - newInputCount int - }{ - {"commitBatch", oldCommitBatchSelector, newCommitBatchSelector, 2, 1}, - {"commitState", oldCommitStateSelector, newCommitStateSelector, 2, 1}, - {"commitBatchWithProof", oldCommitBatchWithProofSelector, newCommitBatchWithProofSelector, 4, 3}, - } - for _, test := range tests { - oldMethod := preSubmitter.Methods[test.name] - newMethod := current.Methods[test.name] - if got := methodSelector(t, preSubmitter, test.name); got != test.oldSelector { - t.Fatalf("pre-submitter %s selector = %s, want %s", test.name, got, test.oldSelector) - } - if got := methodSelector(t, *current, test.name); got != test.newSelector { - t.Fatalf("current %s selector = %s, want %s", test.name, got, test.newSelector) - } - if bytes.Equal(oldMethod.ID, newMethod.ID) { - t.Fatalf("pre-submitter and current %s selectors collide", test.name) - } - if len(oldMethod.Inputs) != test.oldInputCount || len(newMethod.Inputs) != test.newInputCount { - t.Fatalf( - "%s input counts = old %d/current %d, want old %d/current %d", - test.name, - len(oldMethod.Inputs), - len(newMethod.Inputs), - test.oldInputCount, - test.newInputCount, - ) - } - } -} - -func TestSupportedRollupSelectorsHaveNoCollisions(t *testing.T) { - root := repositoryRoot(t) - raw, err := os.ReadFile(filepath.Join( - root, - "node", - "derivation", - "testdata", - "rollup_calldata_fixtures.json", - )) - if err != nil { - t.Fatalf("read shared calldata corpus: %v", err) - } - var corpus calldataCorpus - if err := json.Unmarshal(raw, &corpus); err != nil { - t.Fatalf("parse shared calldata corpus: %v", err) - } - if corpus.SchemaVersion != 1 || len(corpus.Fixtures) != 8 { - t.Fatalf("shared calldata corpus shape = version %d/%d fixtures, want version 1/8 fixtures", corpus.SchemaVersion, len(corpus.Fixtures)) - } - - seen := make(map[string]string, len(corpus.Fixtures)) - for _, fixture := range corpus.Fixtures { - selector := strings.TrimPrefix(strings.ToLower(fixture.Selector), "0x") - data := strings.TrimPrefix(strings.ToLower(fixture.Data), "0x") - if len(selector) != 8 || len(data) < 8 || data[:8] != selector { - t.Fatalf("fixture %s has inconsistent selector/data", fixture.Name) - } - if previous, ok := seen[selector]; ok { - t.Fatalf("selector collision %s between %s and %s", selector, previous, fixture.Name) - } - seen[selector] = fixture.Name - } - - for _, selector := range []string{ - oldCommitBatchSelector, - oldCommitStateSelector, - oldCommitBatchWithProofSelector, - newCommitBatchSelector, - newCommitStateSelector, - newCommitBatchWithProofSelector, - } { - if _, ok := seen[selector]; !ok { - t.Fatalf("shared calldata corpus is missing protected selector %s", selector) - } - } -} diff --git a/bindings/bindings/l1staking.go b/bindings/bindings/l1staking.go new file mode 100644 index 000000000..6ef653abe --- /dev/null +++ b/bindings/bindings/l1staking.go @@ -0,0 +1,3445 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// L1StakingMetaData contains all meta data concerning the L1Staking contract. +var L1StakingMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"_messenger\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChallengeDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChallengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitAddStakerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitRemoveStakersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"Registered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercentage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercentage\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"StakersRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldStakingValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStakingValue\",\"type\":\"uint256\"}],\"name\":\"StakingValueUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"WhitelistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unlockHeight\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MESSENGER\",\"outputs\":[{\"internalType\":\"contractICrossDomainMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OTHER_STAKING\",\"outputs\":[{\"internalType\":\"contractStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"blsPubkey\",\"type\":\"bytes\"}],\"name\":\"blsKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cleanStakerStore\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"deleteList\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"deleteableHeight\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitAddStaker\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitRemoveStakers\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getActiveStakers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"}],\"name\":\"getStakerBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakers\",\"outputs\":[{\"internalType\":\"address[255]\",\"name\":\"\",\"type\":\"address[255]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"getStakersBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"name\":\"getStakersFromBitmap\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"stakerAddrs\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rollupContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_lockBlocks\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isActiveStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStakerInDeleteList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"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\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"removeStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"removedList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"removed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sequencersBitmap\",\"type\":\"uint256\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakerIndexes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"stakerSet\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakers\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"tmPubkey\",\"type\":\"bytes32\"}],\"name\":\"tmKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitAddStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitRemoveStakers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"}],\"name\":\"updateStakingValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"updateWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"verifySignature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"whitelist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"inWhitelist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalLockBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"withdrawals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60c060405234801562000010575f80fd5b5060405162003e1d38038062003e1d833981016040819052620000339162000127565b6001600160a01b03811660805273530000000000000000000000000000000000001560a0526200006262000069565b5062000156565b5f54610100900460ff1615620000d55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161462000125575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000138575f80fd5b81516001600160a01b03811681146200014f575f80fd5b9392505050565b60805160a051613c826200019b5f395f8181610664015281816129530152612bc701525f818161043c01528181610701015281816129240152612b980152613c825ff3fe6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a", +} + +// L1StakingABI is the input ABI used to generate the binding from. +// Deprecated: Use L1StakingMetaData.ABI instead. +var L1StakingABI = L1StakingMetaData.ABI + +// L1StakingBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use L1StakingMetaData.Bin instead. +var L1StakingBin = L1StakingMetaData.Bin + +// DeployL1Staking deploys a new Ethereum contract, binding an instance of L1Staking to it. +func DeployL1Staking(auth *bind.TransactOpts, backend bind.ContractBackend, _messenger common.Address) (common.Address, *types.Transaction, *L1Staking, error) { + parsed, err := L1StakingMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(L1StakingBin), backend, _messenger) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil +} + +// L1Staking is an auto generated Go binding around an Ethereum contract. +type L1Staking struct { + L1StakingCaller // Read-only binding to the contract + L1StakingTransactor // Write-only binding to the contract + L1StakingFilterer // Log filterer for contract events +} + +// L1StakingCaller is an auto generated read-only Go binding around an Ethereum contract. +type L1StakingCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// L1StakingTransactor is an auto generated write-only Go binding around an Ethereum contract. +type L1StakingTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// L1StakingFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type L1StakingFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// L1StakingSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type L1StakingSession struct { + Contract *L1Staking // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// L1StakingCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type L1StakingCallerSession struct { + Contract *L1StakingCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// L1StakingTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type L1StakingTransactorSession struct { + Contract *L1StakingTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// L1StakingRaw is an auto generated low-level Go binding around an Ethereum contract. +type L1StakingRaw struct { + Contract *L1Staking // Generic contract binding to access the raw methods on +} + +// L1StakingCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type L1StakingCallerRaw struct { + Contract *L1StakingCaller // Generic read-only contract binding to access the raw methods on +} + +// L1StakingTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type L1StakingTransactorRaw struct { + Contract *L1StakingTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewL1Staking creates a new instance of L1Staking, bound to a specific deployed contract. +func NewL1Staking(address common.Address, backend bind.ContractBackend) (*L1Staking, error) { + contract, err := bindL1Staking(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil +} + +// NewL1StakingCaller creates a new read-only instance of L1Staking, bound to a specific deployed contract. +func NewL1StakingCaller(address common.Address, caller bind.ContractCaller) (*L1StakingCaller, error) { + contract, err := bindL1Staking(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &L1StakingCaller{contract: contract}, nil +} + +// NewL1StakingTransactor creates a new write-only instance of L1Staking, bound to a specific deployed contract. +func NewL1StakingTransactor(address common.Address, transactor bind.ContractTransactor) (*L1StakingTransactor, error) { + contract, err := bindL1Staking(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &L1StakingTransactor{contract: contract}, nil +} + +// NewL1StakingFilterer creates a new log filterer instance of L1Staking, bound to a specific deployed contract. +func NewL1StakingFilterer(address common.Address, filterer bind.ContractFilterer) (*L1StakingFilterer, error) { + contract, err := bindL1Staking(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &L1StakingFilterer{contract: contract}, nil +} + +// bindL1Staking binds a generic wrapper to an already deployed contract. +func bindL1Staking(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := L1StakingMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_L1Staking *L1StakingRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _L1Staking.Contract.L1StakingCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_L1Staking *L1StakingRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _L1Staking.Contract.L1StakingTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_L1Staking *L1StakingRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _L1Staking.Contract.L1StakingTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_L1Staking *L1StakingCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _L1Staking.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_L1Staking *L1StakingTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _L1Staking.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_L1Staking *L1StakingTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _L1Staking.Contract.contract.Transact(opts, method, params...) +} + +// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. +// +// Solidity: function MESSENGER() view returns(address) +func (_L1Staking *L1StakingCaller) MESSENGER(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "MESSENGER") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. +// +// Solidity: function MESSENGER() view returns(address) +func (_L1Staking *L1StakingSession) MESSENGER() (common.Address, error) { + return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) +} + +// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. +// +// Solidity: function MESSENGER() view returns(address) +func (_L1Staking *L1StakingCallerSession) MESSENGER() (common.Address, error) { + return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) +} + +// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. +// +// Solidity: function OTHER_STAKING() view returns(address) +func (_L1Staking *L1StakingCaller) OTHERSTAKING(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "OTHER_STAKING") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. +// +// Solidity: function OTHER_STAKING() view returns(address) +func (_L1Staking *L1StakingSession) OTHERSTAKING() (common.Address, error) { + return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) +} + +// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. +// +// Solidity: function OTHER_STAKING() view returns(address) +func (_L1Staking *L1StakingCallerSession) OTHERSTAKING() (common.Address, error) { + return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) +} + +// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. +// +// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) +func (_L1Staking *L1StakingCaller) BlsKeys(opts *bind.CallOpts, blsPubkey []byte) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "blsKeys", blsPubkey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. +// +// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) +func (_L1Staking *L1StakingSession) BlsKeys(blsPubkey []byte) (bool, error) { + return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) +} + +// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. +// +// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) +func (_L1Staking *L1StakingCallerSession) BlsKeys(blsPubkey []byte) (bool, error) { + return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_L1Staking *L1StakingCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "challengeDeposit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_L1Staking *L1StakingSession) ChallengeDeposit() (*big.Int, error) { + return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) ChallengeDeposit() (*big.Int, error) { + return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) +} + +// DeleteList is a free data retrieval call binding the contract method 0x797adbde. +// +// Solidity: function deleteList(uint256 ) view returns(address) +func (_L1Staking *L1StakingCaller) DeleteList(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "deleteList", arg0) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// DeleteList is a free data retrieval call binding the contract method 0x797adbde. +// +// Solidity: function deleteList(uint256 ) view returns(address) +func (_L1Staking *L1StakingSession) DeleteList(arg0 *big.Int) (common.Address, error) { + return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) +} + +// DeleteList is a free data retrieval call binding the contract method 0x797adbde. +// +// Solidity: function deleteList(uint256 ) view returns(address) +func (_L1Staking *L1StakingCallerSession) DeleteList(arg0 *big.Int) (common.Address, error) { + return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) +} + +// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. +// +// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) +func (_L1Staking *L1StakingCaller) DeleteableHeight(opts *bind.CallOpts, stakerAddr common.Address) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "deleteableHeight", stakerAddr) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. +// +// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) +func (_L1Staking *L1StakingSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { + return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) +} + +// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. +// +// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) +func (_L1Staking *L1StakingCallerSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { + return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) +} + +// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. +// +// Solidity: function gasLimitAddStaker() view returns(uint256) +func (_L1Staking *L1StakingCaller) GasLimitAddStaker(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "gasLimitAddStaker") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. +// +// Solidity: function gasLimitAddStaker() view returns(uint256) +func (_L1Staking *L1StakingSession) GasLimitAddStaker() (*big.Int, error) { + return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) +} + +// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. +// +// Solidity: function gasLimitAddStaker() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) GasLimitAddStaker() (*big.Int, error) { + return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) +} + +// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. +// +// Solidity: function gasLimitRemoveStakers() view returns(uint256) +func (_L1Staking *L1StakingCaller) GasLimitRemoveStakers(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "gasLimitRemoveStakers") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. +// +// Solidity: function gasLimitRemoveStakers() view returns(uint256) +func (_L1Staking *L1StakingSession) GasLimitRemoveStakers() (*big.Int, error) { + return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) +} + +// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. +// +// Solidity: function gasLimitRemoveStakers() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) GasLimitRemoveStakers() (*big.Int, error) { + return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) +} + +// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. +// +// Solidity: function getActiveStakers() view returns(address[]) +func (_L1Staking *L1StakingCaller) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "getActiveStakers") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. +// +// Solidity: function getActiveStakers() view returns(address[]) +func (_L1Staking *L1StakingSession) GetActiveStakers() ([]common.Address, error) { + return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) +} + +// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. +// +// Solidity: function getActiveStakers() view returns(address[]) +func (_L1Staking *L1StakingCallerSession) GetActiveStakers() ([]common.Address, error) { + return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) +} + +// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. +// +// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) +func (_L1Staking *L1StakingCaller) GetStakerBitmap(opts *bind.CallOpts, _staker common.Address) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "getStakerBitmap", _staker) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. +// +// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) +func (_L1Staking *L1StakingSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { + return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) +} + +// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. +// +// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) +func (_L1Staking *L1StakingCallerSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { + return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) +} + +// GetStakers is a free data retrieval call binding the contract method 0x43352d61. +// +// Solidity: function getStakers() view returns(address[255]) +func (_L1Staking *L1StakingCaller) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "getStakers") + + if err != nil { + return *new([255]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([255]common.Address)).(*[255]common.Address) + + return out0, err + +} + +// GetStakers is a free data retrieval call binding the contract method 0x43352d61. +// +// Solidity: function getStakers() view returns(address[255]) +func (_L1Staking *L1StakingSession) GetStakers() ([255]common.Address, error) { + return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) +} + +// GetStakers is a free data retrieval call binding the contract method 0x43352d61. +// +// Solidity: function getStakers() view returns(address[255]) +func (_L1Staking *L1StakingCallerSession) GetStakers() ([255]common.Address, error) { + return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) +} + +// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. +// +// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) +func (_L1Staking *L1StakingCaller) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "getStakersBitmap", _stakers) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. +// +// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) +func (_L1Staking *L1StakingSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { + return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) +} + +// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. +// +// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) +func (_L1Staking *L1StakingCallerSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { + return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) +} + +// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. +// +// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) +func (_L1Staking *L1StakingCaller) GetStakersFromBitmap(opts *bind.CallOpts, bitmap *big.Int) ([]common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "getStakersFromBitmap", bitmap) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. +// +// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) +func (_L1Staking *L1StakingSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { + return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) +} + +// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. +// +// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) +func (_L1Staking *L1StakingCallerSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { + return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) +} + +// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. +// +// Solidity: function isActiveStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingCaller) IsActiveStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "isActiveStaker", addr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. +// +// Solidity: function isActiveStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingSession) IsActiveStaker(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) +} + +// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. +// +// Solidity: function isActiveStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingCallerSession) IsActiveStaker(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) +} + +// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. +// +// Solidity: function isStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingCaller) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "isStaker", addr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. +// +// Solidity: function isStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingSession) IsStaker(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) +} + +// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. +// +// Solidity: function isStaker(address addr) view returns(bool) +func (_L1Staking *L1StakingCallerSession) IsStaker(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) +} + +// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. +// +// Solidity: function isStakerInDeleteList(address addr) view returns(bool) +func (_L1Staking *L1StakingCaller) IsStakerInDeleteList(opts *bind.CallOpts, addr common.Address) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "isStakerInDeleteList", addr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. +// +// Solidity: function isStakerInDeleteList(address addr) view returns(bool) +func (_L1Staking *L1StakingSession) IsStakerInDeleteList(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) +} + +// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. +// +// Solidity: function isStakerInDeleteList(address addr) view returns(bool) +func (_L1Staking *L1StakingCallerSession) IsStakerInDeleteList(addr common.Address) (bool, error) { + return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) +} + +// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. +// +// Solidity: function messenger() view returns(address) +func (_L1Staking *L1StakingCaller) Messenger(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "messenger") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. +// +// Solidity: function messenger() view returns(address) +func (_L1Staking *L1StakingSession) Messenger() (common.Address, error) { + return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) +} + +// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. +// +// Solidity: function messenger() view returns(address) +func (_L1Staking *L1StakingCallerSession) Messenger() (common.Address, error) { + return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_L1Staking *L1StakingCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_L1Staking *L1StakingSession) Owner() (common.Address, error) { + return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_L1Staking *L1StakingCallerSession) Owner() (common.Address, error) { + return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) +} + +// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. +// +// Solidity: function removedList(address stakerAddr) view returns(bool removed) +func (_L1Staking *L1StakingCaller) RemovedList(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "removedList", stakerAddr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. +// +// Solidity: function removedList(address stakerAddr) view returns(bool removed) +func (_L1Staking *L1StakingSession) RemovedList(stakerAddr common.Address) (bool, error) { + return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) +} + +// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. +// +// Solidity: function removedList(address stakerAddr) view returns(bool removed) +func (_L1Staking *L1StakingCallerSession) RemovedList(stakerAddr common.Address) (bool, error) { + return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_L1Staking *L1StakingCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "rewardPercentage") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_L1Staking *L1StakingSession) RewardPercentage() (*big.Int, error) { + return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) RewardPercentage() (*big.Int, error) { + return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_L1Staking *L1StakingCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "rollupContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_L1Staking *L1StakingSession) RollupContract() (common.Address, error) { + return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_L1Staking *L1StakingCallerSession) RollupContract() (common.Address, error) { + return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_L1Staking *L1StakingCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "slashRemaining") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_L1Staking *L1StakingSession) SlashRemaining() (*big.Int, error) { + return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) SlashRemaining() (*big.Int, error) { + return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) +} + +// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. +// +// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) +func (_L1Staking *L1StakingCaller) StakerIndexes(opts *bind.CallOpts, stakerAddr common.Address) (uint8, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "stakerIndexes", stakerAddr) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. +// +// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) +func (_L1Staking *L1StakingSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { + return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) +} + +// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. +// +// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) +func (_L1Staking *L1StakingCallerSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { + return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) +} + +// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. +// +// Solidity: function stakerSet(uint256 ) view returns(address) +func (_L1Staking *L1StakingCaller) StakerSet(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "stakerSet", arg0) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. +// +// Solidity: function stakerSet(uint256 ) view returns(address) +func (_L1Staking *L1StakingSession) StakerSet(arg0 *big.Int) (common.Address, error) { + return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) +} + +// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. +// +// Solidity: function stakerSet(uint256 ) view returns(address) +func (_L1Staking *L1StakingCallerSession) StakerSet(arg0 *big.Int) (common.Address, error) { + return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) +} + +// Stakers is a free data retrieval call binding the contract method 0x9168ae72. +// +// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingCaller) Stakers(opts *bind.CallOpts, stakerAddr common.Address) (struct { + Addr common.Address + TmKey [32]byte + BlsKey []byte +}, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "stakers", stakerAddr) + + outstruct := new(struct { + Addr common.Address + TmKey [32]byte + BlsKey []byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.TmKey = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.BlsKey = *abi.ConvertType(out[2], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +// Stakers is a free data retrieval call binding the contract method 0x9168ae72. +// +// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingSession) Stakers(stakerAddr common.Address) (struct { + Addr common.Address + TmKey [32]byte + BlsKey []byte +}, error) { + return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) +} + +// Stakers is a free data retrieval call binding the contract method 0x9168ae72. +// +// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingCallerSession) Stakers(stakerAddr common.Address) (struct { + Addr common.Address + TmKey [32]byte + BlsKey []byte +}, error) { + return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) +} + +// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. +// +// Solidity: function stakingValue() view returns(uint256) +func (_L1Staking *L1StakingCaller) StakingValue(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "stakingValue") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. +// +// Solidity: function stakingValue() view returns(uint256) +func (_L1Staking *L1StakingSession) StakingValue() (*big.Int, error) { + return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) +} + +// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. +// +// Solidity: function stakingValue() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) StakingValue() (*big.Int, error) { + return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) +} + +// TmKeys is a free data retrieval call binding the contract method 0x692c565b. +// +// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) +func (_L1Staking *L1StakingCaller) TmKeys(opts *bind.CallOpts, tmPubkey [32]byte) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "tmKeys", tmPubkey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// TmKeys is a free data retrieval call binding the contract method 0x692c565b. +// +// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) +func (_L1Staking *L1StakingSession) TmKeys(tmPubkey [32]byte) (bool, error) { + return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) +} + +// TmKeys is a free data retrieval call binding the contract method 0x692c565b. +// +// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) +func (_L1Staking *L1StakingCallerSession) TmKeys(tmPubkey [32]byte) (bool, error) { + return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) +} + +// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. +// +// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) +func (_L1Staking *L1StakingCaller) VerifySignature(opts *bind.CallOpts, arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "verifySignature", arg0, arg1, arg2, arg3) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. +// +// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) +func (_L1Staking *L1StakingSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { + return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) +} + +// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. +// +// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) +func (_L1Staking *L1StakingCallerSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { + return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) +} + +// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. +// +// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) +func (_L1Staking *L1StakingCaller) Whitelist(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "whitelist", stakerAddr) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. +// +// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) +func (_L1Staking *L1StakingSession) Whitelist(stakerAddr common.Address) (bool, error) { + return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) +} + +// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. +// +// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) +func (_L1Staking *L1StakingCallerSession) Whitelist(stakerAddr common.Address) (bool, error) { + return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) +} + +// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. +// +// Solidity: function withdrawalLockBlocks() view returns(uint256) +func (_L1Staking *L1StakingCaller) WithdrawalLockBlocks(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "withdrawalLockBlocks") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. +// +// Solidity: function withdrawalLockBlocks() view returns(uint256) +func (_L1Staking *L1StakingSession) WithdrawalLockBlocks() (*big.Int, error) { + return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) +} + +// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. +// +// Solidity: function withdrawalLockBlocks() view returns(uint256) +func (_L1Staking *L1StakingCallerSession) WithdrawalLockBlocks() (*big.Int, error) { + return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address staker) view returns(uint256 amount) +func (_L1Staking *L1StakingCaller) Withdrawals(opts *bind.CallOpts, staker common.Address) (*big.Int, error) { + var out []interface{} + err := _L1Staking.contract.Call(opts, &out, "withdrawals", staker) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address staker) view returns(uint256 amount) +func (_L1Staking *L1StakingSession) Withdrawals(staker common.Address) (*big.Int, error) { + return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) +} + +// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. +// +// Solidity: function withdrawals(address staker) view returns(uint256 amount) +func (_L1Staking *L1StakingCallerSession) Withdrawals(staker common.Address) (*big.Int, error) { + return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_L1Staking *L1StakingTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "claimSlashRemaining", receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_L1Staking *L1StakingSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_L1Staking *L1StakingTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_L1Staking *L1StakingTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "claimWithdrawal", receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_L1Staking *L1StakingSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_L1Staking *L1StakingTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) +} + +// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. +// +// Solidity: function cleanStakerStore() returns() +func (_L1Staking *L1StakingTransactor) CleanStakerStore(opts *bind.TransactOpts) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "cleanStakerStore") +} + +// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. +// +// Solidity: function cleanStakerStore() returns() +func (_L1Staking *L1StakingSession) CleanStakerStore() (*types.Transaction, error) { + return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) +} + +// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. +// +// Solidity: function cleanStakerStore() returns() +func (_L1Staking *L1StakingTransactorSession) CleanStakerStore() (*types.Transaction, error) { + return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) +} + +// Initialize is a paid mutator transaction binding the contract method 0x8142951a. +// +// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingTransactor) Initialize(opts *bind.TransactOpts, _rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "initialize", _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) +} + +// Initialize is a paid mutator transaction binding the contract method 0x8142951a. +// +// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) +} + +// Initialize is a paid mutator transaction binding the contract method 0x8142951a. +// +// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingTransactorSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) +} + +// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. +// +// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() +func (_L1Staking *L1StakingTransactor) Register(opts *bind.TransactOpts, tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "register", tmKey, blsKey) +} + +// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. +// +// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() +func (_L1Staking *L1StakingSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { + return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) +} + +// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. +// +// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() +func (_L1Staking *L1StakingTransactorSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { + return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) +} + +// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. +// +// Solidity: function removeStaker(address[] _stakers) returns() +func (_L1Staking *L1StakingTransactor) RemoveStaker(opts *bind.TransactOpts, _stakers []common.Address) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "removeStaker", _stakers) +} + +// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. +// +// Solidity: function removeStaker(address[] _stakers) returns() +func (_L1Staking *L1StakingSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) +} + +// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. +// +// Solidity: function removeStaker(address[] _stakers) returns() +func (_L1Staking *L1StakingTransactorSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_L1Staking *L1StakingTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_L1Staking *L1StakingSession) RenounceOwnership() (*types.Transaction, error) { + return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_L1Staking *L1StakingTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) +} + +// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. +// +// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) +func (_L1Staking *L1StakingTransactor) Slash(opts *bind.TransactOpts, sequencersBitmap *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "slash", sequencersBitmap) +} + +// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. +// +// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) +func (_L1Staking *L1StakingSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) +} + +// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. +// +// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) +func (_L1Staking *L1StakingTransactorSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_L1Staking *L1StakingTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_L1Staking *L1StakingSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_L1Staking *L1StakingTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() +func (_L1Staking *L1StakingTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, _challengeDeposit *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateChallengeDeposit", _challengeDeposit) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() +func (_L1Staking *L1StakingSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) +} + +// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. +// +// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() +func (_L1Staking *L1StakingTransactor) UpdateGasLimitAddStaker(opts *bind.TransactOpts, _gasLimitAdd *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateGasLimitAddStaker", _gasLimitAdd) +} + +// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. +// +// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() +func (_L1Staking *L1StakingSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) +} + +// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. +// +// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) +} + +// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. +// +// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingTransactor) UpdateGasLimitRemoveStakers(opts *bind.TransactOpts, _gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateGasLimitRemoveStakers", _gasLimitRemove) +} + +// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. +// +// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) +} + +// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. +// +// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() +func (_L1Staking *L1StakingTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, _rewardPercentage *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateRewardPercentage", _rewardPercentage) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() +func (_L1Staking *L1StakingSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) +} + +// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. +// +// Solidity: function updateStakingValue(uint256 _stakingValue) returns() +func (_L1Staking *L1StakingTransactor) UpdateStakingValue(opts *bind.TransactOpts, _stakingValue *big.Int) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateStakingValue", _stakingValue) +} + +// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. +// +// Solidity: function updateStakingValue(uint256 _stakingValue) returns() +func (_L1Staking *L1StakingSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) +} + +// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. +// +// Solidity: function updateStakingValue(uint256 _stakingValue) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) +} + +// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. +// +// Solidity: function updateWhitelist(address[] add, address[] remove) returns() +func (_L1Staking *L1StakingTransactor) UpdateWhitelist(opts *bind.TransactOpts, add []common.Address, remove []common.Address) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "updateWhitelist", add, remove) +} + +// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. +// +// Solidity: function updateWhitelist(address[] add, address[] remove) returns() +func (_L1Staking *L1StakingSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) +} + +// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. +// +// Solidity: function updateWhitelist(address[] add, address[] remove) returns() +func (_L1Staking *L1StakingTransactorSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { + return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_L1Staking *L1StakingTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { + return _L1Staking.contract.Transact(opts, "withdraw") +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_L1Staking *L1StakingSession) Withdraw() (*types.Transaction, error) { + return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_L1Staking *L1StakingTransactorSession) Withdraw() (*types.Transaction, error) { + return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) +} + +// L1StakingChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the L1Staking contract. +type L1StakingChallengeDepositUpdatedIterator struct { + Event *L1StakingChallengeDepositUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingChallengeDepositUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingChallengeDepositUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingChallengeDepositUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the L1Staking contract. +type L1StakingChallengeDepositUpdated struct { + OldChallengeDeposit *big.Int + NewChallengeDeposit *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) +func (_L1Staking *L1StakingFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*L1StakingChallengeDepositUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return &L1StakingChallengeDepositUpdatedIterator{contract: _L1Staking.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil +} + +// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) +func (_L1Staking *L1StakingFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingChallengeDepositUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingChallengeDepositUpdated) + if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) +func (_L1Staking *L1StakingFilterer) ParseChallengeDepositUpdated(log types.Log) (*L1StakingChallengeDepositUpdated, error) { + event := new(L1StakingChallengeDepositUpdated) + if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingClaimedIterator is returned from FilterClaimed and is used to iterate over the raw logs and unpacked data for Claimed events raised by the L1Staking contract. +type L1StakingClaimedIterator struct { + Event *L1StakingClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingClaimed represents a Claimed event raised by the L1Staking contract. +type L1StakingClaimed struct { + Staker common.Address + Receiver common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterClaimed is a free log retrieval operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. +// +// Solidity: event Claimed(address indexed staker, address receiver) +func (_L1Staking *L1StakingFilterer) FilterClaimed(opts *bind.FilterOpts, staker []common.Address) (*L1StakingClaimedIterator, error) { + + var stakerRule []interface{} + for _, stakerItem := range staker { + stakerRule = append(stakerRule, stakerItem) + } + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Claimed", stakerRule) + if err != nil { + return nil, err + } + return &L1StakingClaimedIterator{contract: _L1Staking.contract, event: "Claimed", logs: logs, sub: sub}, nil +} + +// WatchClaimed is a free log subscription operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. +// +// Solidity: event Claimed(address indexed staker, address receiver) +func (_L1Staking *L1StakingFilterer) WatchClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingClaimed, staker []common.Address) (event.Subscription, error) { + + var stakerRule []interface{} + for _, stakerItem := range staker { + stakerRule = append(stakerRule, stakerItem) + } + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Claimed", stakerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingClaimed) + if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseClaimed is a log parse operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. +// +// Solidity: event Claimed(address indexed staker, address receiver) +func (_L1Staking *L1StakingFilterer) ParseClaimed(log types.Log) (*L1StakingClaimed, error) { + event := new(L1StakingClaimed) + if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingGasLimitAddStakerUpdatedIterator is returned from FilterGasLimitAddStakerUpdated and is used to iterate over the raw logs and unpacked data for GasLimitAddStakerUpdated events raised by the L1Staking contract. +type L1StakingGasLimitAddStakerUpdatedIterator struct { + Event *L1StakingGasLimitAddStakerUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingGasLimitAddStakerUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingGasLimitAddStakerUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingGasLimitAddStakerUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingGasLimitAddStakerUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingGasLimitAddStakerUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingGasLimitAddStakerUpdated represents a GasLimitAddStakerUpdated event raised by the L1Staking contract. +type L1StakingGasLimitAddStakerUpdated struct { + OldGasLimit *big.Int + NewGasLimit *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterGasLimitAddStakerUpdated is a free log retrieval operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. +// +// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) FilterGasLimitAddStakerUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitAddStakerUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitAddStakerUpdated") + if err != nil { + return nil, err + } + return &L1StakingGasLimitAddStakerUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitAddStakerUpdated", logs: logs, sub: sub}, nil +} + +// WatchGasLimitAddStakerUpdated is a free log subscription operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. +// +// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) WatchGasLimitAddStakerUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitAddStakerUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitAddStakerUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingGasLimitAddStakerUpdated) + if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseGasLimitAddStakerUpdated is a log parse operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. +// +// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) ParseGasLimitAddStakerUpdated(log types.Log) (*L1StakingGasLimitAddStakerUpdated, error) { + event := new(L1StakingGasLimitAddStakerUpdated) + if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingGasLimitRemoveStakersUpdatedIterator is returned from FilterGasLimitRemoveStakersUpdated and is used to iterate over the raw logs and unpacked data for GasLimitRemoveStakersUpdated events raised by the L1Staking contract. +type L1StakingGasLimitRemoveStakersUpdatedIterator struct { + Event *L1StakingGasLimitRemoveStakersUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingGasLimitRemoveStakersUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingGasLimitRemoveStakersUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingGasLimitRemoveStakersUpdated represents a GasLimitRemoveStakersUpdated event raised by the L1Staking contract. +type L1StakingGasLimitRemoveStakersUpdated struct { + OldGasLimit *big.Int + NewGasLimit *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterGasLimitRemoveStakersUpdated is a free log retrieval operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. +// +// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) FilterGasLimitRemoveStakersUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitRemoveStakersUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitRemoveStakersUpdated") + if err != nil { + return nil, err + } + return &L1StakingGasLimitRemoveStakersUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitRemoveStakersUpdated", logs: logs, sub: sub}, nil +} + +// WatchGasLimitRemoveStakersUpdated is a free log subscription operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. +// +// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) WatchGasLimitRemoveStakersUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitRemoveStakersUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitRemoveStakersUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingGasLimitRemoveStakersUpdated) + if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseGasLimitRemoveStakersUpdated is a log parse operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. +// +// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) +func (_L1Staking *L1StakingFilterer) ParseGasLimitRemoveStakersUpdated(log types.Log) (*L1StakingGasLimitRemoveStakersUpdated, error) { + event := new(L1StakingGasLimitRemoveStakersUpdated) + if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the L1Staking contract. +type L1StakingInitializedIterator struct { + Event *L1StakingInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingInitialized represents a Initialized event raised by the L1Staking contract. +type L1StakingInitialized struct { + Version uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_L1Staking *L1StakingFilterer) FilterInitialized(opts *bind.FilterOpts) (*L1StakingInitializedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &L1StakingInitializedIterator{contract: _L1Staking.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_L1Staking *L1StakingFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *L1StakingInitialized) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingInitialized) + if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_L1Staking *L1StakingFilterer) ParseInitialized(log types.Log) (*L1StakingInitialized, error) { + event := new(L1StakingInitialized) + if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the L1Staking contract. +type L1StakingOwnershipTransferredIterator struct { + Event *L1StakingOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingOwnershipTransferred represents a OwnershipTransferred event raised by the L1Staking contract. +type L1StakingOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_L1Staking *L1StakingFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*L1StakingOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &L1StakingOwnershipTransferredIterator{contract: _L1Staking.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_L1Staking *L1StakingFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *L1StakingOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingOwnershipTransferred) + if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_L1Staking *L1StakingFilterer) ParseOwnershipTransferred(log types.Log) (*L1StakingOwnershipTransferred, error) { + event := new(L1StakingOwnershipTransferred) + if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingRegisteredIterator is returned from FilterRegistered and is used to iterate over the raw logs and unpacked data for Registered events raised by the L1Staking contract. +type L1StakingRegisteredIterator struct { + Event *L1StakingRegistered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingRegisteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingRegisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingRegistered represents a Registered event raised by the L1Staking contract. +type L1StakingRegistered struct { + Addr common.Address + TmKey [32]byte + BlsKey []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRegistered is a free log retrieval operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. +// +// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingFilterer) FilterRegistered(opts *bind.FilterOpts) (*L1StakingRegisteredIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Registered") + if err != nil { + return nil, err + } + return &L1StakingRegisteredIterator{contract: _L1Staking.contract, event: "Registered", logs: logs, sub: sub}, nil +} + +// WatchRegistered is a free log subscription operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. +// +// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingFilterer) WatchRegistered(opts *bind.WatchOpts, sink chan<- *L1StakingRegistered) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Registered") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingRegistered) + if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRegistered is a log parse operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. +// +// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) +func (_L1Staking *L1StakingFilterer) ParseRegistered(log types.Log) (*L1StakingRegistered, error) { + event := new(L1StakingRegistered) + if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the L1Staking contract. +type L1StakingRewardPercentageUpdatedIterator struct { + Event *L1StakingRewardPercentageUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingRewardPercentageUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingRewardPercentageUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingRewardPercentageUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the L1Staking contract. +type L1StakingRewardPercentageUpdated struct { + OldPercentage *big.Int + NewPercentage *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) +func (_L1Staking *L1StakingFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*L1StakingRewardPercentageUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return &L1StakingRewardPercentageUpdatedIterator{contract: _L1Staking.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil +} + +// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) +func (_L1Staking *L1StakingFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingRewardPercentageUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingRewardPercentageUpdated) + if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) +func (_L1Staking *L1StakingFilterer) ParseRewardPercentageUpdated(log types.Log) (*L1StakingRewardPercentageUpdated, error) { + event := new(L1StakingRewardPercentageUpdated) + if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the L1Staking contract. +type L1StakingSlashRemainingClaimedIterator struct { + Event *L1StakingSlashRemainingClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingSlashRemainingClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingSlashRemainingClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingSlashRemainingClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the L1Staking contract. +type L1StakingSlashRemainingClaimed struct { + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) +func (_L1Staking *L1StakingFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts) (*L1StakingSlashRemainingClaimedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "SlashRemainingClaimed") + if err != nil { + return nil, err + } + return &L1StakingSlashRemainingClaimedIterator{contract: _L1Staking.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil +} + +// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) +func (_L1Staking *L1StakingFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashRemainingClaimed) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "SlashRemainingClaimed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingSlashRemainingClaimed) + if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) +func (_L1Staking *L1StakingFilterer) ParseSlashRemainingClaimed(log types.Log) (*L1StakingSlashRemainingClaimed, error) { + event := new(L1StakingSlashRemainingClaimed) + if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the L1Staking contract. +type L1StakingSlashedIterator struct { + Event *L1StakingSlashed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingSlashedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingSlashedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingSlashedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingSlashed represents a Slashed event raised by the L1Staking contract. +type L1StakingSlashed struct { + Stakers []common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashed is a free log retrieval operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. +// +// Solidity: event Slashed(address[] stakers) +func (_L1Staking *L1StakingFilterer) FilterSlashed(opts *bind.FilterOpts) (*L1StakingSlashedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Slashed") + if err != nil { + return nil, err + } + return &L1StakingSlashedIterator{contract: _L1Staking.contract, event: "Slashed", logs: logs, sub: sub}, nil +} + +// WatchSlashed is a free log subscription operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. +// +// Solidity: event Slashed(address[] stakers) +func (_L1Staking *L1StakingFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashed) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Slashed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingSlashed) + if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashed is a log parse operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. +// +// Solidity: event Slashed(address[] stakers) +func (_L1Staking *L1StakingFilterer) ParseSlashed(log types.Log) (*L1StakingSlashed, error) { + event := new(L1StakingSlashed) + if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingStakersRemovedIterator is returned from FilterStakersRemoved and is used to iterate over the raw logs and unpacked data for StakersRemoved events raised by the L1Staking contract. +type L1StakingStakersRemovedIterator struct { + Event *L1StakingStakersRemoved // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingStakersRemovedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingStakersRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingStakersRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingStakersRemovedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingStakersRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingStakersRemoved represents a StakersRemoved event raised by the L1Staking contract. +type L1StakingStakersRemoved struct { + Stakers []common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterStakersRemoved is a free log retrieval operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. +// +// Solidity: event StakersRemoved(address[] stakers) +func (_L1Staking *L1StakingFilterer) FilterStakersRemoved(opts *bind.FilterOpts) (*L1StakingStakersRemovedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakersRemoved") + if err != nil { + return nil, err + } + return &L1StakingStakersRemovedIterator{contract: _L1Staking.contract, event: "StakersRemoved", logs: logs, sub: sub}, nil +} + +// WatchStakersRemoved is a free log subscription operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. +// +// Solidity: event StakersRemoved(address[] stakers) +func (_L1Staking *L1StakingFilterer) WatchStakersRemoved(opts *bind.WatchOpts, sink chan<- *L1StakingStakersRemoved) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakersRemoved") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingStakersRemoved) + if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseStakersRemoved is a log parse operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. +// +// Solidity: event StakersRemoved(address[] stakers) +func (_L1Staking *L1StakingFilterer) ParseStakersRemoved(log types.Log) (*L1StakingStakersRemoved, error) { + event := new(L1StakingStakersRemoved) + if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingStakingValueUpdatedIterator is returned from FilterStakingValueUpdated and is used to iterate over the raw logs and unpacked data for StakingValueUpdated events raised by the L1Staking contract. +type L1StakingStakingValueUpdatedIterator struct { + Event *L1StakingStakingValueUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingStakingValueUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingStakingValueUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingStakingValueUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingStakingValueUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingStakingValueUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingStakingValueUpdated represents a StakingValueUpdated event raised by the L1Staking contract. +type L1StakingStakingValueUpdated struct { + OldStakingValue *big.Int + NewStakingValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterStakingValueUpdated is a free log retrieval operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. +// +// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) +func (_L1Staking *L1StakingFilterer) FilterStakingValueUpdated(opts *bind.FilterOpts) (*L1StakingStakingValueUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakingValueUpdated") + if err != nil { + return nil, err + } + return &L1StakingStakingValueUpdatedIterator{contract: _L1Staking.contract, event: "StakingValueUpdated", logs: logs, sub: sub}, nil +} + +// WatchStakingValueUpdated is a free log subscription operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. +// +// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) +func (_L1Staking *L1StakingFilterer) WatchStakingValueUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingStakingValueUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakingValueUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingStakingValueUpdated) + if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseStakingValueUpdated is a log parse operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. +// +// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) +func (_L1Staking *L1StakingFilterer) ParseStakingValueUpdated(log types.Log) (*L1StakingStakingValueUpdated, error) { + event := new(L1StakingStakingValueUpdated) + if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingWhitelistUpdatedIterator is returned from FilterWhitelistUpdated and is used to iterate over the raw logs and unpacked data for WhitelistUpdated events raised by the L1Staking contract. +type L1StakingWhitelistUpdatedIterator struct { + Event *L1StakingWhitelistUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingWhitelistUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingWhitelistUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingWhitelistUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingWhitelistUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingWhitelistUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingWhitelistUpdated represents a WhitelistUpdated event raised by the L1Staking contract. +type L1StakingWhitelistUpdated struct { + Add []common.Address + Remove []common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWhitelistUpdated is a free log retrieval operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. +// +// Solidity: event WhitelistUpdated(address[] add, address[] remove) +func (_L1Staking *L1StakingFilterer) FilterWhitelistUpdated(opts *bind.FilterOpts) (*L1StakingWhitelistUpdatedIterator, error) { + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "WhitelistUpdated") + if err != nil { + return nil, err + } + return &L1StakingWhitelistUpdatedIterator{contract: _L1Staking.contract, event: "WhitelistUpdated", logs: logs, sub: sub}, nil +} + +// WatchWhitelistUpdated is a free log subscription operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. +// +// Solidity: event WhitelistUpdated(address[] add, address[] remove) +func (_L1Staking *L1StakingFilterer) WatchWhitelistUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingWhitelistUpdated) (event.Subscription, error) { + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "WhitelistUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingWhitelistUpdated) + if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWhitelistUpdated is a log parse operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. +// +// Solidity: event WhitelistUpdated(address[] add, address[] remove) +func (_L1Staking *L1StakingFilterer) ParseWhitelistUpdated(log types.Log) (*L1StakingWhitelistUpdated, error) { + event := new(L1StakingWhitelistUpdated) + if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// L1StakingWithdrawnIterator is returned from FilterWithdrawn and is used to iterate over the raw logs and unpacked data for Withdrawn events raised by the L1Staking contract. +type L1StakingWithdrawnIterator struct { + Event *L1StakingWithdrawn // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *L1StakingWithdrawnIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(L1StakingWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(L1StakingWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *L1StakingWithdrawnIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *L1StakingWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// L1StakingWithdrawn represents a Withdrawn event raised by the L1Staking contract. +type L1StakingWithdrawn struct { + Addr common.Address + UnlockHeight *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawn is a free log retrieval operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. +// +// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) +func (_L1Staking *L1StakingFilterer) FilterWithdrawn(opts *bind.FilterOpts, addr []common.Address) (*L1StakingWithdrawnIterator, error) { + + var addrRule []interface{} + for _, addrItem := range addr { + addrRule = append(addrRule, addrItem) + } + + logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Withdrawn", addrRule) + if err != nil { + return nil, err + } + return &L1StakingWithdrawnIterator{contract: _L1Staking.contract, event: "Withdrawn", logs: logs, sub: sub}, nil +} + +// WatchWithdrawn is a free log subscription operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. +// +// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) +func (_L1Staking *L1StakingFilterer) WatchWithdrawn(opts *bind.WatchOpts, sink chan<- *L1StakingWithdrawn, addr []common.Address) (event.Subscription, error) { + + var addrRule []interface{} + for _, addrItem := range addr { + addrRule = append(addrRule, addrItem) + } + + logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Withdrawn", addrRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(L1StakingWithdrawn) + if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawn is a log parse operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. +// +// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) +func (_L1Staking *L1StakingFilterer) ParseWithdrawn(log types.Log) (*L1StakingWithdrawn, error) { + event := new(L1StakingWithdrawn) + if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/bindings/bindings/l1staking_more.go b/bindings/bindings/l1staking_more.go new file mode 100644 index 000000000..c3a973380 --- /dev/null +++ b/bindings/bindings/l1staking_more.go @@ -0,0 +1,25 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "encoding/json" + + "morph-l2/bindings/solc" +) + +const L1StakingStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1027_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakingValue\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawalLockBlocks\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitAddStaker\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitRemoveStakers\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_uint256\"},{\"astId\":1013,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"whitelist\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"removedList\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerSet\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_address)1025_storage\"},{\"astId\":1017,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerIndexes\",\"offset\":0,\"slot\":\"415\",\"type\":\"t_mapping(t_address,t_uint8)\"},{\"astId\":1018,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteList\",\"offset\":0,\"slot\":\"416\",\"type\":\"t_array(t_address)dyn_storage\"},{\"astId\":1019,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteableHeight\",\"offset\":0,\"slot\":\"417\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1020,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakers\",\"offset\":0,\"slot\":\"418\",\"type\":\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"blsKeys\",\"offset\":0,\"slot\":\"419\",\"type\":\"t_mapping(t_bytes_memory_ptr,t_bool)\"},{\"astId\":1022,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"tmKeys\",\"offset\":0,\"slot\":\"420\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1023,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawals\",\"offset\":0,\"slot\":\"421\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1024,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"422\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_address)1025_storage\":{\"encoding\":\"inplace\",\"label\":\"address[255]\",\"numberOfBytes\":\"8160\"},\"t_array(t_address)dyn_storage\":{\"encoding\":\"dynamic_array\",\"label\":\"address[]\",\"numberOfBytes\":\"32\"},\"t_array(t_uint256)1026_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1027_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_bytes_memory_ptr\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_bytes_storage\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct Types.StakerInfo)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_struct(StakerInfo)1028_storage\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_address,t_uint8)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint8)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint8\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_bytes_memory_ptr,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes_memory_ptr\",\"value\":\"t_bool\"},\"t_struct(StakerInfo)1028_storage\":{\"encoding\":\"inplace\",\"label\":\"struct Types.StakerInfo\",\"numberOfBytes\":\"96\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" + +var L1StakingStorageLayout = new(solc.StorageLayout) + +var L1StakingDeployedBin = "0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f14610940578063f2fde38b1461095f578063f4fe7fef1461097e575f80fd5b8063d51c90a9146108a6578063dd4785f5146108bb578063df155033146108fc575f80fd5b8063c7cd469a116100b7578063c7cd469a14610849578063cde4cd1114610868578063d096c3c614610887575f80fd5b8063ab8c53dc146107e9578063ae81de53146107fe578063bfa02ba91461081d575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db914610797578063a3066aab146107ab578063a4f209b0146107ca575f80fd5b8063927ede2d1461070a5780639b19251a1461073d5780639d48f4171461076b575f80fd5b80638a565ac31161016c5780638a565ac3146106935780638da5cb5b146106b25780639168ae72146106dc575f80fd5b80637a9262a2146106155780638142951a14610641578063831cfb5814610660575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610595578063797adbde146105bb5780637a4e87c3146105da575f80fd5b8063692c565b146105335780636f1e853314610562578063715018a614610581575f80fd5b80634d64903a1161022c5780634d64903a146104ea57806352d472eb146104ff5780636801579114610514575f80fd5b806341de239b1461049557806343352d61146104aa57806345bc4d10146104cb575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461043b5780633ccfd60b1461046d5780633ee2a1f914610481575f80fd5b8063320ff860146103bf57806335928991146103de5780633a9bbede146103fd575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613d4e565b61099d565b005b34801561035a575f80fd5b50610312610369366004613db5565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613dd5565b610e5f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031c565b3480156103ca575f80fd5b5061034d6103d9366004613dec565b610e8b565b3480156103e9575f80fd5b5061034d6103f8366004613dd5565b61127a565b348015610408575f80fd5b5061042b610417366004613db5565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610446575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b348015610478575f80fd5b5061034d611341565b34801561048c575f80fd5b5061034d611579565b3480156104a0575f80fd5b5061031260995481565b3480156104b5575f80fd5b506104be61158b565b60405161031c9190613e94565b3480156104d6575f80fd5b506103126104e5366004613dd5565b6115de565b3480156104f5575f80fd5b5061031260985481565b34801561050a575f80fd5b50610312609a5481565b34801561051f575f80fd5b5061042b61052e366004613db5565b61199a565b34801561053e575f80fd5b5061042b61054d366004613dd5565b6101a46020525f908152604090205460ff1681565b34801561056d575f80fd5b5061042b61057c366004613db5565b611a69565b34801561058c575f80fd5b5061034d611b09565b3480156105a0575f80fd5b5061042b6105af366004613f23565b60019695505050505050565b3480156105c6575f80fd5b5061039a6105d5366004613dd5565b611b1a565b3480156105e5575f80fd5b5061042b6105f4366004613fc9565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610620575f80fd5b5061031261062f366004613db5565b6101a56020525f908152604090205481565b34801561064c575f80fd5b5061034d61065b366004614003565b611b50565b34801561066b575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b5061034d6106ad366004613dd5565b61211a565b3480156106bd575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661039a565b3480156106e7575f80fd5b506106fb6106f6366004613db5565b6121d7565b60405161031c939291906140bc565b348015610715575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610748575f80fd5b5061042b610757366004613db5565b609e6020525f908152604090205460ff1681565b348015610776575f80fd5b5061078a610785366004613dd5565b612297565b60405161031c91906140f9565b3480156107a2575f80fd5b5061078a6123ce565b3480156107b6575f80fd5b5061034d6107c5366004613db5565b6125b0565b3480156107d5575f80fd5b5061034d6107e4366004613dd5565b612721565b3480156107f4575f80fd5b50610312609d5481565b348015610809575f80fd5b5061034d610818366004613dd5565b6127eb565b348015610828575f80fd5b5060975461039a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610854575f80fd5b5061034d610863366004614152565b6128a8565b348015610873575f80fd5b5061034d610882366004613db5565b612ac6565b348015610892575f80fd5b506103126108a1366004613db5565b612b41565b3480156108b1575f80fd5b50610312609b5481565b3480156108c6575f80fd5b506108ea6108d5366004613db5565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b348015610907575f80fd5b5061042b610916366004613db5565b73ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b34801561094b575f80fd5b5061031261095a3660046141b9565b612be2565b34801561096a575f80fd5b5061034d610979366004613db5565b612d55565b348015610989575f80fd5b5061034d610998366004613dd5565b612e09565b335f818152609e602052604090205460ff16610a1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a2602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f616c7265616479207265676973746572656400000000000000000000000000006044820152606401610a11565b8215801590610ac557505f8381526101a4602052604090205460ff16155b610b2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b6579000000000000006044820152606401610a11565b8151610100148015610b5e57506101a382604051610b4991906141f8565b9081526040519081900360200190205460ff16155b610bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420626c73207075626b657900000000000000000000000000006044820152606401610a11565b6098543414610c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b6040518060600160405280610c413390565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610cc190826142a8565b50905050610cd4610ccf3390565b612ec6565b60016101a383604051610ce791906141f8565b9081526040805191829003602090810190922080549315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610d643390565b8484604051610d75939291906140bc565b60405180910390a1335f9081526101a260209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff168152600182015492810192909252600281018054610e5a9484019190610dd590614213565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0190614213565b8015610e4c5780601f10610e2357610100808354040283529160200191610e4c565b820191905f5260205f20905b815481529060010190602001808311610e2f57829003601f168201915b505050505081525050613033565b505050565b60a08160ff8110610e6e575f80fd5b015473ffffffffffffffffffffffffffffffffffffffff16905081565b610e93613186565b5f5b815181101561123657610ec0828281518110610eb357610eb36143c4565b602002602001015161199a565b610f4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a11565b6101a55f838381518110610f6257610f626143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20545f1461100c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611019904361441e565b6101a55f84848151811061102f5761102f6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550611096828281518110611089576110896143c4565b6020026020010151613207565b8181815181106110a8576110a86143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f8585815181106110fd576110fd6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205460405161114e91815260200190565b60405180910390a2609e5f83838151811061116b5761116b6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f8484815181106111d2576111d26143c4565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610e95565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b60405180910390a16112778161333a565b50565b611282613186565b5f8111801561129457506101a6548114155b6112fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61134a3361199a565b6113b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f6e6c7920616374697665207374616b657200000000000000000000000000006044820152606401610a11565b335f9081526101a5602052604090205415611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611434904361441e565b335f8181526101a5602052604090209190915561145090613207565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f81518110611510576115106143c4565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b611581613186565b61158961345d565b565b611593613bdf565b60408051611fe08101918290529060a09060ff9082845b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116115aa575050505050905090565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610a11565b61167f6137ae565b5f61168983612297565b90505f805b82518110156118b0575f6101a55f8584815181106116ae576116ae6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541115611765576101a55f84838151811061170c5761170c6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f90556098548261175e919061441e565b91506118a8565b6117ac83828151811061177a5761177a6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b6118a8576098546117bd908361441e565b91506117d4838281518110611089576110896143c4565b609e5f8483815181106117e9576117e96143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f858481518110611850576118506143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b60010161168e565b505f6064609a54836118c29190614431565b6118cc9190614448565b90506118d88183614480565b609d5f8282546118e8919061441e565b90915550506097546119109073ffffffffffffffffffffffffffffffffffffffff1682613821565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161193f91906140f9565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848360405161197691906140f9565b60405180910390a16119878361333a565b925050506119956001606555565b919050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff1681036119d057505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611a089060019060ff16614493565b60ff1660ff8110611a1b57611a1b6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16148015611a63575073ffffffffffffffffffffffffffffffffffffffff82165f9081526101a16020526040902054155b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff168103611a9f57505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611ad79060019060ff16614493565b60ff1660ff8110611aea57611aea6143c4565b015473ffffffffffffffffffffffffffffffffffffffff161492915050565b611b11613186565b6115895f6138f8565b6101a08181548110611b2a575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b5f54610100900460ff1615808015611b6e57505f54600160ff909116105b80611b875750303b158015611b8757505f5460ff166001145b611c13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a11565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611c6f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8816611cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610a11565b5f8711611d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b5f8611611dbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b5f8511611e27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b7300006044820152606401610a11565b5f8311611e90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b6572000000006044820152606401610a11565b5f8211611ef9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b6572736044820152606401610a11565b5f84118015611f09575060648411155b611f94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f74616765000000000000000000000000000000000000000000000000000000006064820152608401610a11565b611f9c61396e565b611fa4613a0c565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015612110575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b612122613186565b5f811180156121335750609c548114155b612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f79101611335565b6101a26020525f908152604090208054600182015460028301805473ffffffffffffffffffffffffffffffffffffffff90931693919261221690614213565b80601f016020809104026020016040519081016040528092919081815260200182805461224290614213565b801561228d5780601f106122645761010080835404028352916020019161228d565b820191905f5260205f20905b81548152906001019060200180831161227057829003601f168201915b5050505050905083565b6060600182901c5f5b81156122c7576122b181600161441e565b90506122be600183614480565b821691506122a0565b8067ffffffffffffffff8111156122e0576122e0613c48565b604051908082528060200260200182016040528015612309578160200160208202803683370190505b5092505f60015b60ff8160ff16116123c557600160ff82161b8616156123b35760a0612336600183614493565b60ff1660ff8110612349576123496143c4565b0154855173ffffffffffffffffffffffffffffffffffffffff90911690869084908110612378576123786143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526123a882600161441e565b9150828210156123c5575b806123bd816144ac565b915050612310565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff8110156124b7575f60a08260ff8110612416576124166143c4565b015473ffffffffffffffffffffffffffffffffffffffff161480159061247857506101a15f60a08360ff811061244e5761244e6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054155b156124af5782612487816144ca565b935050600182828151811061249e5761249e6143c4565b911515602092830291909101909101525b6001016123f9565b505f8267ffffffffffffffff8111156124d2576124d2613c48565b6040519080825280602002602001820160405280156124fb578160200160208202803683370190505b5090505f805b60ff8110156125a65783818151811061251c5761251c6143c4565b60200260200101511561259e5760a08160ff811061253c5761253c6143c4565b0154835173ffffffffffffffffffffffffffffffffffffffff9091169084908490811061256b5761256b6143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528161259a816144ca565b9250505b600101612501565b5090949350505050565b6125b86137ae565b335f9081526101a5602052604090205461262e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7769746864726177616c206e6f742065786973740000000000000000000000006044820152606401610a11565b335f9081526101a560205260409020544310156126a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f7769746864726177616c206c6f636b65640000000000000000000000000000006044820152606401610a11565b335f9081526101a560205260408120556126bf61345d565b6040805173ffffffffffffffffffffffffffffffffffffffff83168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a261271781609854613821565b6112776001606555565b612729613186565b5f81118015612739575060648111155b80156127475750609a548114155b6127ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610a11565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba9101611335565b6127f3613186565b5f811180156128045750609b548114155b61286a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c9101611335565b6128b0613186565b5f5b838110156129fa57609f5f8686848181106128cf576128cf6143c4565b90506020020160208101906128e49190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f205460ff1615612974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e2072656d6f766564206c69737400000000000000000000000000000000006044820152606401610a11565b6001609e5f87878581811061298b5761298b6143c4565b90506020020160208101906129a09190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556001016128b2565b505f5b81811015612a8257609e5f848484818110612a1a57612a1a6143c4565b9050602002016020810190612a2f9190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001016129fd565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac862284848484604051612ab89493929190614553565b60405180910390a150505050565b612ace613186565b612ad66137ae565b609d54612ae38282613821565b5f609d556040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a1506112776001606555565b5f612b4b82611a69565b612bb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b5073ffffffffffffffffffffffffffffffffffffffff165f90815261019f6020526040902054600160ff9091161b90565b5f60ff821115612c4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e6473000000006044820152606401610a11565b5f5b82811015612d4e57612c82848483818110612c6d57612c6d6143c4565b905060200201602081019061057c9190613db5565b612ce8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b61019f5f858584818110612cfe57612cfe6143c4565b9050602002016020810190612d139190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054600160ff90911681901b929092179101612c50565b5092915050565b612d5d613186565b73ffffffffffffffffffffffffffffffffffffffff8116612e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a11565b611277816138f8565b612e11613186565b5f81118015612e2257506098548114155b612e88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de743689101611335565b5f5b60ff8160ff161015612fd0575f60a060ff808416908110612eeb57612eeb6143c4565b015473ffffffffffffffffffffffffffffffffffffffff1603612fc8578160a08260ff1660ff8110612f1f57612f1f6143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055612f6e816001614584565b73ffffffffffffffffffffffffffffffffffffffff929092165f90815261019f6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff9093169290921790915550565b600101612ec8565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f736c6f742066756c6c00000000000000000000000000000000000000000000006044820152606401610a11565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016130a2919061459d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f604051808303815f87803b15801561316d575f80fd5b505af115801561317f573d5f803e3d5ffd5b5050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314611589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a11565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526101a1602052604090205415613294576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f616c726561647920696e2064656c6574654c69737400000000000000000000006044820152606401610a11565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316179055609954613311904361441e565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526101a16020526040902055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016133a991906140f9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f5b6101a05481101561127757436101a15f6101a08481548110613483576134836143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020541161379c5760a0600161019f5f6101a085815481106134d5576134d56143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054613513919060ff16614493565b60ff1660ff8110613526576135266143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110613568576135686143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556101a080546101a2929190849081106135d9576135d96143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560018101829055906136446002830182613bfe565b50506101a15f6101a0838154811061365e5761365e6143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040018120556101a080546136a090600190614480565b815481106136b0576136b06143c4565b5f918252602090912001546101a0805473ffffffffffffffffffffffffffffffffffffffff90921691839081106136e9576136e96143c4565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101a080548061374057613740614626565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905561345f565b806137a6816144ca565b91505061345f565b60026065540361381a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a11565b6002606555565b80156138ed575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461387d576040519150601f19603f3d011682016040523d82523d5f602084013e613882565b606091505b5050905080610e5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610a11565b5050565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16613a04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613aaa565b5f54610100900460ff16613aa2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613b49565b5f54610100900460ff16613b40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589336138f8565b5f54610100900460ff166138f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b60405180611fe0016040528060ff906020820280368337509192915050565b508054613c0a90614213565b5f825580601f10613c19575050565b601f0160209004905f5260205f209081019061127791905b80821115613c44575f8155600101613c31565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613cbc57613cbc613c48565b604052919050565b5f82601f830112613cd3575f80fd5b813567ffffffffffffffff811115613ced57613ced613c48565b613d1e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613c75565b818152846020838601011115613d32575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613d5f575f80fd5b82359150602083013567ffffffffffffffff811115613d7c575f80fd5b613d8885828601613cc4565b9150509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611995575f80fd5b5f60208284031215613dc5575f80fd5b613dce82613d92565b9392505050565b5f60208284031215613de5575f80fd5b5035919050565b5f6020808385031215613dfd575f80fd5b823567ffffffffffffffff80821115613e14575f80fd5b818501915085601f830112613e27575f80fd5b813581811115613e3957613e39613c48565b8060051b9150613e4a848301613c75565b8181529183018401918481019088841115613e63575f80fd5b938501935b83851015613e8857613e7985613d92565b82529385019390850190613e68565b98975050505050505050565b611fe0810181835f5b60ff811015613ed257815173ffffffffffffffffffffffffffffffffffffffff16835260209283019290910190600101613e9d565b50505092915050565b5f8083601f840112613eeb575f80fd5b50813567ffffffffffffffff811115613f02575f80fd5b6020830191508360208260051b8501011115613f1c575f80fd5b9250929050565b5f805f805f8060808789031215613f38575f80fd5b86359550602087013567ffffffffffffffff80821115613f56575f80fd5b613f628a838b01613edb565b9097509550604089013594506060890135915080821115613f81575f80fd5b818901915089601f830112613f94575f80fd5b813581811115613fa2575f80fd5b8a6020828501011115613fb3575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613fd9575f80fd5b813567ffffffffffffffff811115613fef575f80fd5b613ffb84828501613cc4565b949350505050565b5f805f805f805f60e0888a031215614019575f80fd5b61402288613d92565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561406b578181015183820152602001614053565b50505f910152565b5f815180845261408a816020860160208601614051565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6140f06060830184614073565b95945050505050565b602080825282518282018190525f9190848201906040850190845b8181101561414657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614114565b50909695505050505050565b5f805f8060408587031215614165575f80fd5b843567ffffffffffffffff8082111561417c575f80fd5b61418888838901613edb565b909650945060208701359150808211156141a0575f80fd5b506141ad87828801613edb565b95989497509550505050565b5f80602083850312156141ca575f80fd5b823567ffffffffffffffff8111156141e0575f80fd5b6141ec85828601613edb565b90969095509350505050565b5f8251614209818460208701614051565b9190910192915050565b600181811c9082168061422757607f821691505b60208210810361425e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610e5a57805f5260205f20601f840160051c810160208510156142895750805b601f840160051c820191505b8181101561317f575f8155600101614295565b815167ffffffffffffffff8111156142c2576142c2613c48565b6142d6816142d08454614213565b84614264565b602080601f831160018114614328575f84156142f25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556143bc565b5f858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561437457888601518255948401946001909101908401614355565b50858210156143b057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611a6357611a636143f1565b8082028115828204841417611a6357611a636143f1565b5f8261447b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115611a6357611a636143f1565b60ff8281168282160390811115611a6357611a636143f1565b5f60ff821660ff81036144c1576144c16143f1565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036144fa576144fa6143f1565b5060010190565b8183525f60208085019450825f5b858110156145485773ffffffffffffffffffffffffffffffffffffffff61453583613d92565b168752958201959082019060010161450f565b509495945050505050565b604081525f614566604083018688614501565b8281036020840152614579818587614501565b979650505050505050565b60ff8181168382160190811115611a6357611a636143f1565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152613ffb6080840182614073565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201525f6146156080830185614073565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a" + +func init() { + if err := json.Unmarshal([]byte(L1StakingStorageLayoutJSON), L1StakingStorageLayout); err != nil { + panic(err) + } + + layouts["L1Staking"] = L1StakingStorageLayout + deployedBytecodes["L1Staking"] = L1StakingDeployedBin +} diff --git a/bindings/bindings/rollup.go b/bindings/bindings/rollup.go index 8b52b5a21..a3e5d0a88 100644 --- a/bindings/bindings/rollup.go +++ b/bindings/bindings/rollup.go @@ -40,10 +40,17 @@ type IRollupBatchDataInput struct { WithdrawalRoot [32]byte } +// IRollupBatchSignatureInput is an auto generated low-level Go binding around an user-defined struct. +type IRollupBatchSignatureInput struct { + SignedSequencersBitmap *big.Int + SequencerSets []byte + Signature []byte +} + // RollupMetaData contains all meta data concerning the Rollup contract. var RollupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddr\",\"type\":\"address\"}],\"name\":\"SubmitterContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_submitterContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newSubmitter\",\"type\":\"address\"}],\"name\":\"initialize4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"pendingBatchCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"submitterContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a060405234801562000010575f80fd5b506040516200599d3803806200599d83398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b60805161583f6200015e5f395f81816106ab015261481e015261583f5ff3fe608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610b2c578063f2fde38b14610b4b578063f8fa010f14610b6a578063fb1e8b0414610b89575f80fd5b8063d279c19114610ac4578063d8dc99d214610ae3578063de8b303514610af8578063dff7827e14610b17575f80fd5b8063c5553892116100d8578063c555389214610a5e578063cd4edc6914610a7d578063ce5db8d614610a90578063cf9a674514610aa5575f80fd5b8063b3e0a50914610a01578063b8d0a1b014610a20578063bedb86fb14610a3f575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d14610983578063b31a77d3146109ae578063b3484425146109c3578063b35dac4e146109e2575f80fd5b8063a415d8dc14610921578063a479265d1461094f578063a4f209b014610964575f80fd5b80638f1d3776116101a35780638f1d377614610802578063910129d4146108b257806397fc007c146108e3578063a3c9e94c14610902575f80fd5b806388b1ea09146107a15780638da5cb5b146107ba5780638ef622a8146107d7575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107245780636c578c1d1461074f578063715018a61461076e578063728cdbca14610782575f80fd5b80635f77cf1d1461069a57806361267290146106e657806367caa37a14610705575f80fd5b806341f756da1161027957806341f756da146105df57806357e0af6c146105f25780635c975abb146106115780635ef7a94a14610628575f80fd5b80632b7ac3f3146105745780633b70c18a146105ab5780633e001b66146105ca575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e36600461529d565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046152ca565b610b9e565b005b348015610406575f80fd5b506103f9610415366004615328565b610c70565b348015610425575f80fd5b506103a261043436600461529d565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004615370565b610fb5565b34801561047b575f80fd5b506103f961048a3660046153bf565b6114db565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be36600461529d565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee36600461529d565b61189a565b3480156104fe575f80fd5b506103cc61050d36600461529d565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc61053836600461529d565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc61056336600461529d565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c54610593906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105b6575f80fd5b50609b54610593906001600160a01b031681565b3480156105d5575f80fd5b506103cc60aa5481565b6103f96105ed36600461544d565b6118c8565b3480156105fd575f80fd5b506103f961060c36600461529d565b611b66565b34801561061c575f80fd5b5060655460ff166103a2565b348015610633575f80fd5b5061067161064236600461529d565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106a5575f80fd5b506106cd7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b3480156106f1575f80fd5b506103f961070036600461529d565b611c11565b348015610710575f80fd5b506103f961071f36600461544d565b611dee565b34801561072f575f80fd5b506103cc61073e36600461529d565b60ab6020525f908152604090205481565b34801561075a575f80fd5b506103f96107693660046152ca565b612139565b348015610779575f80fd5b506103f96121f6565b34801561078d575f80fd5b506103f961079c366004615487565b612209565b3480156107ac575f80fd5b5060a6546103a29060ff1681565b3480156107c5575f80fd5b506033546001600160a01b0316610593565b3480156107e2575f80fd5b506103cc6107f13660046152ca565b60ae6020525f908152604090205481565b34801561080d575f80fd5b5061086e61081c36600461529d565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108bd575f80fd5b506103a26108cc36600461529d565b5f90815260a4602052604090206003015460ff1690565b3480156108ee575f80fd5b506103f96108fd3660046152ca565b612512565b34801561090d575f80fd5b50609754610593906001600160a01b031681565b34801561092c575f80fd5b506103a261093b3660046152ca565b609f6020525f908152604090205460ff1681565b34801561095a575f80fd5b506103cc60995481565b34801561096f575f80fd5b506103f961097e36600461529d565b6125f5565b34801561098e575f80fd5b506103cc61099d3660046152ca565b60a56020525f908152604090205481565b3480156109b9575f80fd5b506103cc60a85481565b3480156109ce575f80fd5b506103f96109dd3660046154e2565b6126a5565b3480156109ed575f80fd5b506103f96109fc3660046152ca565b6129b2565b348015610a0c575f80fd5b506103f9610a1b366004615370565b612a0b565b348015610a2b575f80fd5b506103f9610a3a3660046154e2565b612d9c565b348015610a4a575f80fd5b506103f9610a59366004615556565b612e25565b348015610a69575f80fd5b506103f9610a7836600461529d565b612f63565b6103f9610a8b366004615588565b613006565b348015610a9b575f80fd5b506103cc60985481565b348015610ab0575f80fd5b506103f9610abf36600461529d565b613598565b348015610acf575f80fd5b506103f9610ade3660046152ca565b61370f565b348015610aee575f80fd5b506103cc60ac5481565b348015610b03575f80fd5b506103a2610b1236600461529d565b6137ce565b348015610b22575f80fd5b506103cc609a5481565b348015610b37575f80fd5b506103f9610b4636600461529d565b613818565b348015610b56575f80fd5b506103f9610b653660046152ca565b6138bb565b348015610b75575f80fd5b506103f9610b843660046152ca565b613948565b348015610b94575f80fd5b506103cc60a95481565b610ba6613e4d565b6001600160a01b0381165f908152609f602052604090205460ff1615610c135760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c78613e4d565b5f8111610cc75760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c0a565b5f80610cd38585613ea7565b915091505f610ce6836001015160c01c90565b5f81815260a160205260409020549091508214610d455760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f60a181610d5387856155dd565b81526020019081526020015f205414610dd35760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b609d548111610e4a5760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b610e556001826155f0565b609e555b8315610fad57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610e9381613f4f565b5f81815260a16020526040812055610eaa816137ce565b15610f05575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ef59084906155dd565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f65575060a85481145b15610f6f575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e59575b505050505050565b60a854156110055760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b61100d614002565b5f806110198484613ea7565b915091505f61102c836001015160c01c90565b5f81815260a16020526040902054909150821461108b5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6110948161189a565b6110e05760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b6110e9816137ce565b156111365760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a4602052604090206003015460ff16156111975760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c0a565b5f81815260a260205260409020600101544210156111f75760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c0a565b605983015160a05f61120a6001856155f0565b81526020019081526020015f2054146112655760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f81815260a06020526040902054156112c05760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c0a565b80609d54600101146113145760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b609d819055600160a35f611329866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561137861136b846011015160c01c90565b600985015160c01c614055565b61138181613f4f565b60a25f61138f6001846155f0565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113eb90846155f0565b81526020019081526020015f205f905560ad5f60018361140b91906155f0565b81526020019081526020015f205f905560a45f60018361142b91906155f0565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d6114b7866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a8541561152b5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611533614002565b60ac54609e545f90815260a260205260408120549091429161155591906155dd565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d19190615603565b6115db91906155dd565b109050811580156115e95750805b15611650575f6115ff6080890160608a0161561a565b61ffff16116116505760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b81806116595750805b6116a55760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c0a565b5f6116bb6116b660208a018a61563b565b613ea7565b5090505f6116cd826001015160c01c90565b6116d89060016155dd565b5f81815260ad60205260408120549192509015611778575f49156117645760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c0a565b505f81815260ad6020526040902054611793565b61179061178860208c018c61569c565b60ff16614112565b90505b61179e8a5f8361424d565b5f806117aa8b8b613ea7565b915091505f6117bd836001015160c01c90565b905080609e54146118105760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461186c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b5f81815260a2602052604090204260019091015561188b838b8b6147af565b50505050505050505050505050565b5f81815260a26020526040812054158015906118c257505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611934573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195891906156bc565b6119a45760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a854156119f45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6119fc614002565b5f49611a4a5760405162461bcd60e51b815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aae573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad29190615603565b611adc91906155dd565b1015611b44575f611af3608083016060840161561a565b61ffff1611611b445760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b5f611b55611788602084018461569c565b9050611b6282338361424d565b5050565b611b6e613e4d565b5f81118015611b7f57506099548114155b611bcb5760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c0a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c3157505f5460ff8083169116105b611ca35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055611cbe613e4d565b5f5460ff1660ff16600214611d155760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c0a565b81611d885760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c0a565b609e545f90815260ab6020526040902054611db157609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7e91906156bc565b611eca5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b60a85415611f1a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b611f22614002565b5f4915611f715760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c0a565b5f611f826116b6602084018461563b565b5090505f611f94826001015160c01c90565b611f9f9060016155dd565b5f81815260ad60205260409020549091506120225760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c0a565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015612086573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120aa9190615603565b6120b491906155dd565b101561211c575f6120cb608085016060860161561a565b61ffff161161211c5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c0a565b61213483335f84815260ad602052604090205461424d565b505050565b612141613e4d565b6001600160a01b0381165f908152609f602052604090205460ff166121a85760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c0a565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c65565b6121fe613e4d565b6122075f614962565b565b5f54610100900460ff161580801561222757505f54600160ff909116105b806122405750303b15801561224057505f5460ff166001145b6122b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805460ff1916600117905580156122d3575f805461ff0019166101001790555b6001600160a01b03861615806122f057506001600160a01b038516155b15612327576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03871661237d5760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c0a565b6123856149cb565b61238d614a4f565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612509575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61251a613e4d565b6001600160a01b038116158015906125405750609c546001600160a01b03828116911614155b61258c5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c0a565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6125fd613e4d565b5f8111801561260d575060648111155b801561261b575060a9548114155b6126675760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c0a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c05565b60a854156126f55760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6126fd614002565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612769573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061278d91906156bc565b6127d95760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c0a565b5f806127e58686613ea7565b915091505f6127f8836001015160c01c90565b5f81815260a1602052604090205490915082146128575760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b612860816137ce565b6128ac5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c0a565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916128e8916155dd565b11612967575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526129629183916001600160a01b031690614ad3565b612509565b6129728386866147af565b61250981336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614c32565b6129ba613e4d565b60aa80545f9091556129cc8282614cfe565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c05565b612a13613e4d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612a8a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c0a565b5f80612a968484613ea7565b915091505f612aa9836001015160c01c90565b90508015612af95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c0a565b5f612b05846079015190565b905080612b545760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c0a565b600984015160c01c15612ba95760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c0a565b5f612bb5856019015190565b03612c025760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c0a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c2e856039015190565b14612c7b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c0a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612da88686613ea7565b915091505f612dbb836001015160c01c90565b5f81815260a160205260409020549091508214612e1a5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6125098386866147af565b612e2d613e4d565b8015612f3157612e3b614da3565b60a65460ff1615612ef05760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612e8f9084906155dd565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f39614dfd565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f13565b50565b612f6b613e4d565b5f81118015612f7c575060ac548114155b612fc85760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c0a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c05565b335f908152609f602052604090205460ff166130645760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c0a565b60a854156130b45760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b6130bc614002565b60a65460ff161561310f5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c0a565b8167ffffffffffffffff16609d541061316a5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a1602052604090205481146131d15760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c0a565b6131e48267ffffffffffffffff1661189a565b6132305760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132ab5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c0a565b67ffffffffffffffff82165f90815260a26020526040902060010154421061333b5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c0a565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190615603565b3410156133fe5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c0a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161351691815260200190565b60405180910390a35f609d54600161352e91906155dd565b90505b609e548111613586578267ffffffffffffffff168114613574576099545f82815260a260205260408120600101805490919061356e9084906155dd565b90915550505b8061357e816156d7565b915050613531565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135b857505f5460ff8083169116105b61362a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff831617610100179055613645613e4d565b815f036136945760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c0a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b335f90815260a560205260408120549081900361376e5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c0a565b335f90815260a560205260408120556137878282614cfe565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137c291815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118c25750505f90815260a46020526040902060030154610100900460ff161590565b613820613e4d565b5f8111801561383157506098548114155b61387d5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c0a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c05565b6138c3613e4d565b6001600160a01b03811661393f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c0a565b612f6081614962565b5f54600490610100900460ff1615801561396857505f5460ff8083169116105b6139da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c0a565b5f805461ffff191660ff8316176101001790556139f5613e4d565b6001600160a01b03821615801590613a1657505f826001600160a01b03163b115b613a625760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c0a565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90613ac6908490614e36565b905060a081901c15613b1a5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610c0a565b6040515f602482018190528291613bab908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052614e36565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f90613c12908790614e36565b90506001600160a01b0383163014613c6c5760405162461bcd60e51b815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610c0a565b81158015613c7957505f81115b613cc55760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610c0a565b609d54609e5414613d185760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c0a565b60a85415613d685760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c0a565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560975490516001600160a01b03898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861617905550505f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c05565b6033546001600160a01b031633146122075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c0a565b5f805f613eb48585614ebf565b90505f8160ff165f03613ed557613ecb8686614f2f565b9094509050613f41565b8160ff1660011480613eea57508160ff166002145b15613ef957613ecb8686614f98565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c0a565b808420925050509250929050565b5f81815260a260205260409020600301546001600160a01b031680613f72575050565b6001600160a01b0381165f90815260ae602052604090205480613fd75760405162461bcd60e51b815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610c0a565b613fe26001826155f0565b6001600160a01b039092165f90815260ae60205260409020919091555050565b60655460ff16156122075760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c0a565b805f03614060575050565b8082035f5b8281101561410c5761010081840381111561407f57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b1580156140e2575f80fd5b505af11580156140f4573d5f803e3d5ffd5b50505050610100830192505061010081019050614065565b50505050565b5f816002036141a1575f6040515f5b80498061412e575061413d565b60208202830152600101614121565b60208102808320920160405290925090508061419b5760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c0a565b50919050565b600149156142175760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c0a565b5f4915614225575f496118c2565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261425c602085018561569c565b60ff1611156142ad5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c0a565b60808301356142fe5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c0a565b60a083013561434f5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c0a565b5f806143616116b6602087018761563b565b915091505f614374836001015160c01c90565b90505f60a1816143858460016155dd565b81526020019081526020015f2054146143e05760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c0a565b609e5481146144315760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c0a565b5f81815260a16020526040902054821461448d5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c0a565b5f81815260ab60205260409020546080870135146144ed5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c0a565b5f6144fc846011015160c01c90565b90505f61452861451260608a0160408b0161570e565b61452260808b0160608c0161561a565b84614feb565b905061453a6080890160608a0161561a565b60019384019361ffff91909116929092019160f99061455c60208b018b61569c565b60ff161061456957506101015b60408051828101909152955061458e8661458660208c018c61569c565b60ff1661502f565b60c084901b60018701526145bc866145ac60808c0160608d0161561a565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161460c60208b018b61569c565b60ff161061463e5761463e8661462860608c0160408d0161570e565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156146a75760a7545f90815260a46020526040902060020154609954429161469a916155dd565b6146a491906155f0565b90505b604051806080016040528042815260200182609854426146c791906155dd565b6146d191906155dd565b81526020016146e660608d0160408e0161570e565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561476589615036565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b806147fc5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c0a565b5f61480b846001015160c01c90565b90505f614819856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614848876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a84861490a885160f81c90565b858888866040518663ffffffff1660e01b815260040161492e959493929190615727565b5f6040518083038186803b158015614944575f80fd5b505afa158015614956573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16614a475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b612207615075565b5f54610100900460ff16614acb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6122076150fd565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614b5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614b7e9190615603565b5f86815260a46020526040902060010154909150614b9d9082906155dd565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a590915281208054909190614bdc9084906155dd565b9091555050604051614bef90849061578a565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614c5690846157b6565b614c6091906157cd565b9050614c6c81836155f0565b60aa5f828254614c7c91906155dd565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614ca89084906155dd565b9091555050604051614cbb90849061578a565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611b62575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614d4d576040519150601f19603f3d011682016040523d82523d5f602084013e614d52565b606091505b50509050806121345760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c0a565b614dab614002565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614de03390565b6040516001600160a01b03909116815260200160405180910390a1565b614e05615182565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614de0565b5f805f805f855160208701885afa91503d905060208114821615614e5e5760205f803e5f5192505b818015614e6b5750806020145b614eb75760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610c0a565b505092915050565b5f81614f0d5760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c0a565b82825f818110614f1f57614f1f615805565b919091013560f81c949350505050565b5f8160f9811015614f825760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c0a565b6040519150808483378082016040529250929050565b5f816101018114614f825760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c0a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f9181016150208161ffff8716866151d4565b82900390912095945050505050565b8082535050565b6001600160a01b03811615612f60576001600160a01b0381165f90815260ae6020526040812080546001929061506d9084906155dd565b909155505050565b5f54610100900460ff166150f15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b6065805460ff19169055565b5f54610100900460ff166151795760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c0a565b61220733614962565b60655460ff166122075760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c0a565b5f825f036151e3575082615296565b609b546001600160a01b03165f5b84811015615290576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015615257573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061527b9190615603565b875250602090950194600193840193016151f1565b50849150505b9392505050565b5f602082840312156152ad575f80fd5b5035919050565b80356001600160a01b0381168114614248575f80fd5b5f602082840312156152da575f80fd5b615296826152b4565b5f8083601f8401126152f3575f80fd5b50813567ffffffffffffffff81111561530a575f80fd5b602083019150836020828501011115615321575f80fd5b9250929050565b5f805f6040848603121561533a575f80fd5b833567ffffffffffffffff811115615350575f80fd5b61535c868287016152e3565b909790965060209590950135949350505050565b5f8060208385031215615381575f80fd5b823567ffffffffffffffff811115615397575f80fd5b6153a3858286016152e3565b90969095509350505050565b5f60e0828403121561419b575f80fd5b5f805f805f606086880312156153d3575f80fd5b853567ffffffffffffffff808211156153ea575f80fd5b6153f689838a016153af565b9650602088013591508082111561540b575f80fd5b61541789838a016152e3565b9096509450604088013591508082111561542f575f80fd5b5061543c888289016152e3565b969995985093965092949392505050565b5f6020828403121561545d575f80fd5b813567ffffffffffffffff811115615473575f80fd5b61547f848285016153af565b949350505050565b5f805f805f8060c0878903121561549c575f80fd5b6154a5876152b4565b95506154b3602088016152b4565b94506154c1604088016152b4565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156154f5575f80fd5b843567ffffffffffffffff8082111561550c575f80fd5b615518888389016152e3565b90965094506020870135915080821115615530575f80fd5b5061553d878288016152e3565b95989497509550505050565b8015158114612f60575f80fd5b5f60208284031215615566575f80fd5b813561529681615549565b803567ffffffffffffffff81168114614248575f80fd5b5f8060408385031215615599575f80fd5b6155a283615571565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118c2576118c26155b0565b818103818111156118c2576118c26155b0565b5f60208284031215615613575f80fd5b5051919050565b5f6020828403121561562a575f80fd5b813561ffff81168114615296575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261566e575f80fd5b83018035915067ffffffffffffffff821115615688575f80fd5b602001915036819003821315615321575f80fd5b5f602082840312156156ac575f80fd5b813560ff81168114615296575f80fd5b5f602082840312156156cc575f80fd5b815161529681615549565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615707576157076155b0565b5060010190565b5f6020828403121561571e575f80fd5b61529682615571565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156157a9576020818601810151858301520161578f565b505f920191825250919050565b80820281158282048414176118c2576118c26155b0565b5f82615800577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60a060405234801562000010575f80fd5b506040516200578d3803806200578d83398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b60805161562f6200015e5f395f81816106a20152614408015261562f5ff3fe608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a", } // RollupABI is the input ABI used to generate the binding from. @@ -401,21 +408,21 @@ func (_Rollup *RollupCallerSession) BatchChallengedSuccess(batchIndex *big.Int) // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) { var out []interface{} err := _Rollup.contract.Call(opts, &out, "batchDataStore", batchIndex) outstruct := new(struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }) if err != nil { return *outstruct, err @@ -424,7 +431,7 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big outstruct.OriginTimestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.FinalizeTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) outstruct.BlockNumber = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.Submitter = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + outstruct.SignedSequencersBitmap = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) return *outstruct, err @@ -432,24 +439,24 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) func (_Rollup *RollupSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) func (_Rollup *RollupCallerSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } @@ -829,6 +836,37 @@ func (_Rollup *RollupCallerSession) IsChallenger(challengerAddress common.Addres return _Rollup.Contract.IsChallenger(&_Rollup.CallOpts, challengerAddress) } +// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. +// +// Solidity: function l1StakingContract() view returns(address) +func (_Rollup *RollupCaller) L1StakingContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Rollup.contract.Call(opts, &out, "l1StakingContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. +// +// Solidity: function l1StakingContract() view returns(address) +func (_Rollup *RollupSession) L1StakingContract() (common.Address, error) { + return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) +} + +// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. +// +// Solidity: function l1StakingContract() view returns(address) +func (_Rollup *RollupCallerSession) L1StakingContract() (common.Address, error) { + return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) +} + // LastCommittedBatchIndex is a free data retrieval call binding the contract method 0x121dcd50. // // Solidity: function lastCommittedBatchIndex() view returns(uint256) @@ -984,37 +1022,6 @@ func (_Rollup *RollupCallerSession) Paused() (bool, error) { return _Rollup.Contract.Paused(&_Rollup.CallOpts) } -// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. -// -// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) -func (_Rollup *RollupCaller) PendingBatchCount(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { - var out []interface{} - err := _Rollup.contract.Call(opts, &out, "pendingBatchCount", submitter) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. -// -// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) -func (_Rollup *RollupSession) PendingBatchCount(submitter common.Address) (*big.Int, error) { - return _Rollup.Contract.PendingBatchCount(&_Rollup.CallOpts, submitter) -} - -// PendingBatchCount is a free data retrieval call binding the contract method 0x8ef622a8. -// -// Solidity: function pendingBatchCount(address submitter) view returns(uint256 count) -func (_Rollup *RollupCallerSession) PendingBatchCount(submitter common.Address) (*big.Int, error) { - return _Rollup.Contract.PendingBatchCount(&_Rollup.CallOpts, submitter) -} - // ProofRewardPercent is a free data retrieval call binding the contract method 0xfb1e8b04. // // Solidity: function proofRewardPercent() view returns(uint256) @@ -1199,37 +1206,6 @@ func (_Rollup *RollupCallerSession) RollupDelayPeriod() (*big.Int, error) { return _Rollup.Contract.RollupDelayPeriod(&_Rollup.CallOpts) } -// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. -// -// Solidity: function submitterContract() view returns(address) -func (_Rollup *RollupCaller) SubmitterContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Rollup.contract.Call(opts, &out, "submitterContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. -// -// Solidity: function submitterContract() view returns(address) -func (_Rollup *RollupSession) SubmitterContract() (common.Address, error) { - return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) -} - -// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. -// -// Solidity: function submitterContract() view returns(address) -func (_Rollup *RollupCallerSession) SubmitterContract() (common.Address, error) { - return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) -} - // Verifier is a free data retrieval call binding the contract method 0x2b7ac3f3. // // Solidity: function verifier() view returns(address) @@ -1376,67 +1352,67 @@ func (_Rollup *RollupTransactorSession) ClaimReward(receiver common.Address) (*t return _Rollup.Contract.ClaimReward(&_Rollup.TransactOpts, receiver) } -// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. +// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() -func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() +func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput, batchSignatureInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. +// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() -func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() +func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. +// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() -func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() +func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, batchSignatureInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) } -// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. +// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() -func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitState", batchDataInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() +func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitState", batchDataInput, batchSignatureInput) } -// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. +// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() -func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() +func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) } -// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. +// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() -func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() +func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) } // FinalizeBatch is a paid mutator transaction binding the contract method 0x13361101. @@ -1483,23 +1459,23 @@ func (_Rollup *RollupTransactorSession) ImportGenesisBatch(_batchHeader []byte) // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "initialize", _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize", _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactorSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactorSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize2 is a paid mutator transaction binding the contract method 0x61267290. @@ -1544,27 +1520,6 @@ func (_Rollup *RollupTransactorSession) Initialize3(_rollupDelayPeriod *big.Int) return _Rollup.Contract.Initialize3(&_Rollup.TransactOpts, _rollupDelayPeriod) } -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. -// -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupTransactor) Initialize4(opts *bind.TransactOpts, _newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "initialize4", _newSubmitter) -} - -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. -// -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) -} - -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. -// -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupTransactorSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) -} - // ProveState is a paid mutator transaction binding the contract method 0xb3484425. // // Solidity: function proveState(bytes _batchHeader, bytes _batchProof) returns() @@ -3295,159 +3250,6 @@ func (_Rollup *RollupFilterer) ParseRevertBatch(log types.Log) (*RollupRevertBat return event, nil } -// RollupSubmitterContractUpdatedIterator is returned from FilterSubmitterContractUpdated and is used to iterate over the raw logs and unpacked data for SubmitterContractUpdated events raised by the Rollup contract. -type RollupSubmitterContractUpdatedIterator struct { - Event *RollupSubmitterContractUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *RollupSubmitterContractUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(RollupSubmitterContractUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(RollupSubmitterContractUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *RollupSubmitterContractUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *RollupSubmitterContractUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// RollupSubmitterContractUpdated represents a SubmitterContractUpdated event raised by the Rollup contract. -type RollupSubmitterContractUpdated struct { - OldAddr common.Address - NewAddr common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSubmitterContractUpdated is a free log retrieval operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. -// -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) -func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterOpts, oldAddr []common.Address, newAddr []common.Address) (*RollupSubmitterContractUpdatedIterator, error) { - - var oldAddrRule []interface{} - for _, oldAddrItem := range oldAddr { - oldAddrRule = append(oldAddrRule, oldAddrItem) - } - var newAddrRule []interface{} - for _, newAddrItem := range newAddr { - newAddrRule = append(newAddrRule, newAddrItem) - } - - logs, sub, err := _Rollup.contract.FilterLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) - if err != nil { - return nil, err - } - return &RollupSubmitterContractUpdatedIterator{contract: _Rollup.contract, event: "SubmitterContractUpdated", logs: logs, sub: sub}, nil -} - -// WatchSubmitterContractUpdated is a free log subscription operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. -// -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) -func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpts, sink chan<- *RollupSubmitterContractUpdated, oldAddr []common.Address, newAddr []common.Address) (event.Subscription, error) { - - var oldAddrRule []interface{} - for _, oldAddrItem := range oldAddr { - oldAddrRule = append(oldAddrRule, oldAddrItem) - } - var newAddrRule []interface{} - for _, newAddrItem := range newAddr { - newAddrRule = append(newAddrRule, newAddrItem) - } - - logs, sub, err := _Rollup.contract.WatchLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(RollupSubmitterContractUpdated) - if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSubmitterContractUpdated is a log parse operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. -// -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) -func (_Rollup *RollupFilterer) ParseSubmitterContractUpdated(log types.Log) (*RollupSubmitterContractUpdated, error) { - event := new(RollupSubmitterContractUpdated) - if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - // RollupUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the Rollup contract. type RollupUnpausedIterator struct { Event *RollupUnpaused // Event containing the contract specifics and raw log diff --git a/bindings/bindings/rollup_more.go b/bindings/bindings/rollup_more.go index e0a97d7fc..a78f509fd 100644 --- a/bindings/bindings/rollup_more.go +++ b/bindings/bindings/rollup_more.go @@ -9,11 +9,11 @@ import ( "morph-l2/bindings/solc" ) -const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1032_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"submitterContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1030,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"pendingBatchCount\",\"offset\":0,\"slot\":\"174\",\"type\":\"t_mapping(t_address,t_uint256)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1033_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1034_storage\"},\"t_struct(BatchChallenge)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1034_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" +const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"l1StakingContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1030_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1032_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1033_storage\"},\"t_struct(BatchChallenge)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" var RollupStorageLayout = new(solc.StorageLayout) -var RollupDeployedBin = "0x608060405260043610610369575f3560e01c806388b1ea09116101c8578063b3e0a509116100fd578063d279c1911161009d578063e3fff1dd1161006d578063e3fff1dd14610ba1578063f2fde38b14610bc0578063f8fa010f14610bdf578063fb1e8b0414610bfe575f80fd5b8063d279c19114610b39578063d8dc99d214610b58578063de8b303514610b6d578063dff7827e14610b8c575f80fd5b8063c5553892116100d8578063c555389214610ad3578063cd4edc6914610af2578063ce5db8d614610b05578063cf9a674514610b1a575f80fd5b8063b3e0a50914610a76578063b8d0a1b014610a95578063bedb86fb14610ab4575f80fd5b8063a415d8dc11610168578063abc8d68d11610143578063abc8d68d146109f8578063b31a77d314610a23578063b348442514610a38578063b35dac4e14610a57575f80fd5b8063a415d8dc14610996578063a479265d146109c4578063a4f209b0146109d9575f80fd5b80638f1d3776116101a35780638f1d377614610850578063910129d41461091a57806397fc007c1461094b578063a3c9e94c1461096a575f80fd5b806388b1ea09146107e25780638da5cb5b146107fb5780638ef622a814610825575f80fd5b80632b7ac3f31161029e5780635f77cf1d1161023e57806368589dfa1161021957806368589dfa146107655780636c578c1d14610790578063715018a6146107af578063728cdbca146107c3575f80fd5b80635f77cf1d146106db578063612672901461072757806367caa37a14610746575f80fd5b806341f756da1161027957806341f756da1461060657806357e0af6c146106195780635c975abb146106385780635ef7a94a1461064f575f80fd5b80632b7ac3f3146105745780633b70c18a146105c55780633e001b66146105f1575f80fd5b80631544ba3a1161030957806321e2f9e0116102e457806321e2f9e0146104d45780632362f03e146104f35780632571098d1461051e5780632a213ba114610549575f80fd5b80631544ba3a1461047057806318463fb01461048f57806318af3b2b146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e3660046162b5565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f43660046162ef565b610c13565b005b348015610406575f80fd5b506103f961041536600461634d565b610d37565b348015610425575f80fd5b506103a26104343660046162b5565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b366004616395565b61112c565b34801561047b575f80fd5b506103f961048a3660046163e4565b611777565b34801561049a575f80fd5b506103cc60a75481565b3480156104af575f80fd5b506103a26104be3660046162b5565b5f90815260a26020526040902060010154421090565b3480156104df575f80fd5b506103a26104ee3660046162b5565b611bec565b3480156104fe575f80fd5b506103cc61050d3660046162b5565b60a16020525f908152604090205481565b348015610529575f80fd5b506103cc6105383660046162b5565b60a06020525f908152604090205481565b348015610554575f80fd5b506103cc6105633660046162b5565b60ad6020525f908152604090205481565b34801561057f575f80fd5b50609c546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103ae565b3480156105d0575f80fd5b50609b546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105fc575f80fd5b506103cc60aa5481565b6103f9610614366004616472565b611c1a565b348015610624575f80fd5b506103f96106333660046162b5565b611f47565b348015610643575f80fd5b5060655460ff166103a2565b34801561065a575f80fd5b506106a56106693660046162b5565b60a26020525f908152604090208054600182015460028301546003909301549192909173ffffffffffffffffffffffffffffffffffffffff1684565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080016103ae565b3480156106e6575f80fd5b5061070e7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b348015610732575f80fd5b506103f96107413660046162b5565b61200c565b348015610751575f80fd5b506103f9610760366004616472565b612271565b348015610770575f80fd5b506103cc61077f3660046162b5565b60ab6020525f908152604090205481565b34801561079b575f80fd5b506103f96107aa3660046162ef565b612665565b3480156107ba575f80fd5b506103f9612774565b3480156107ce575f80fd5b506103f96107dd3660046164ac565b612787565b3480156107ed575f80fd5b5060a6546103a29060ff1681565b348015610806575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff166105a0565b348015610830575f80fd5b506103cc61083f3660046162ef565b60ae6020525f908152604090205481565b34801561085b575f80fd5b506108c961086a3660046162b5565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b348015610925575f80fd5b506103a26109343660046162b5565b5f90815260a4602052604090206003015460ff1690565b348015610956575f80fd5b506103f96109653660046162ef565b612b50565b348015610975575f80fd5b506097546105a09073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109a1575f80fd5b506103a26109b03660046162ef565b609f6020525f908152604090205460ff1681565b3480156109cf575f80fd5b506103cc60995481565b3480156109e4575f80fd5b506103f96109f33660046162b5565b612c74565b348015610a03575f80fd5b506103cc610a123660046162ef565b60a56020525f908152604090205481565b348015610a2e575f80fd5b506103cc60a85481565b348015610a43575f80fd5b506103f9610a52366004616507565b612d3e565b348015610a62575f80fd5b506103f9610a713660046162ef565b613133565b348015610a81575f80fd5b506103f9610a90366004616395565b613199565b348015610aa0575f80fd5b506103f9610aaf366004616507565b6135d3565b348015610abf575f80fd5b506103f9610ace36600461657b565b613676565b348015610ade575f80fd5b506103f9610aed3660046162b5565b613809565b6103f9610b003660046165ad565b6138c6565b348015610b10575f80fd5b506103cc60985481565b348015610b25575f80fd5b506103f9610b343660046162b5565b613fdb565b348015610b44575f80fd5b506103f9610b533660046162ef565b6141c0565b348015610b63575f80fd5b506103cc60ac5481565b348015610b78575f80fd5b506103a2610b873660046162b5565b6142a6565b348015610b97575f80fd5b506103cc609a5481565b348015610bac575f80fd5b506103f9610bbb3660046162b5565b6142fd565b348015610bcb575f80fd5b506103f9610bda3660046162ef565b6143ba565b348015610bea575f80fd5b506103f9610bf93660046162ef565b61446e565b348015610c09575f80fd5b506103cc60a95481565b610c1b614aa4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610caf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610d3f614aa4565b5f8111610da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610ca6565b5f80610db48585614b25565b915091505f610dc7836001015160c01c90565b5f81815260a160205260409020549091508214610e40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b5f60a181610e4e8785616602565b81526020019081526020015f205414610ee8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b609d548111610f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b610f84600182616615565b609e555b831561112457604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a3610fc281614be7565b5f81815260a16020526040812055610fd9816142a6565b1561105f575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091611031908490616602565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a854158015906110dc575060a85481145b156110e6575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610f88575b505050505050565b60a85415611196576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b61119e614cdb565b5f806111aa8484614b25565b915091505f6111bd836001015160c01c90565b5f81815260a160205260409020549091508214611236576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b61123f81611bec565b6112a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca6565b6112ae816142a6565b15611315576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610ca6565b5f81815260a4602052604090206003015460ff1615611390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610ca6565b5f81815260a2602052604090206001015442101561140a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610ca6565b605983015160a05f61141d600185616615565b81526020019081526020015f205414611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca6565b5f81815260a0602052604090205415611507576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610ca6565b80609d5460010114611575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca6565b609d819055600160a35f61158a866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a060205260409020556115f76115ea846011015160c01c90565b600985015160c01c614d48565b61160081614be7565b60a25f61160e600184616615565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab919061166a9084616615565b81526020019081526020015f205f905560ad5f60018361168a9190616615565b81526020019081526020015f205f905560a45f6001836116aa9190616615565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611753866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156117e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6117e9614cdb565b60ac54609e545f90815260a260205260408120549091429161180b9190616602565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118a19190616628565b6118ab9190616602565b109050811580156118b95750805b1561193a575f6118cf6080890160608a0161663f565b61ffff161161193a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b81806119435750805b6119a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610ca6565b5f6119bf6119ba60208a018a616660565b614b25565b5090505f6119d1826001015160c01c90565b6119dc906001616602565b5f81815260ad60205260408120549192509015611a96575f4915611a82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610ca6565b505f81815260ad6020526040902054611ab1565b611aae611aa660208c018c6166c1565b60ff16614e12565b90505b611abc8a5f83614f81565b5f80611ac88b8b614b25565b915091505f611adb836001015160c01c90565b905080609e5414611b48576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610ca6565b5f81815260a160205260409020548214611bbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b5f81815260a26020526040902042600190910155611bdd838b8b6155a6565b50505050505050505050505050565b5f81815260a2602052604081205415801590611c1457505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611ca0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cc491906166e1565b611d2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b60a85415611d94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b611d9c614cdb565b5f49611e04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6d75737420636172727920626c6f6200000000000000000000000000000000006044820152606401610ca6565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e75573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e999190616628565b611ea39190616602565b1015611f25575f611eba608083016060840161663f565b61ffff1611611f25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b5f611f36611aa660208401846166c1565b9050611f43823383614f81565b5050565b611f4f614aa4565b5f81118015611f6057506099548114155b611fc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610ca6565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561202c57505f5460ff8083169116105b6120b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556120f0614aa4565b5f5460ff1660ff16600214612161576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610ca6565b816121ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610ca6565b609e545f90815260ab602052604090205461221757609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa1580156122f7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061231b91906166e1565b612381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b60a854156123eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6123f3614cdb565b5f491561245c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610ca6565b5f61246d6119ba6020840184616660565b5090505f61247f826001015160c01c90565b61248a906001616602565b5f81815260ad6020526040902054909150612527576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610ca6565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015612598573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bc9190616628565b6125c69190616602565b1015612648575f6125dd608085016060860161663f565b61ffff1611612648576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610ca6565b61266083335f84815260ad6020526040902054614f81565b505050565b61266d614aa4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff166126fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610ca6565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610d2c565b61277c614aa4565b6127855f615780565b565b5f54610100900460ff16158080156127a557505f54600160ff909116105b806127be5750303b1580156127be57505f5460ff166001145b61284a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156128a6575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806128dd575073ffffffffffffffffffffffffffffffffffffffff8516155b15612914576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8716612991576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610ca6565b6129996157f6565b6129a1615894565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612b47575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612b58614aa4565b73ffffffffffffffffffffffffffffffffffffffff811615801590612b985750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612bfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610ca6565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612c7c614aa4565b5f81118015612c8c575060648111155b8015612c9a575060a9548114155b612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610ca6565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101612000565b60a85415612da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b612db0614cdb565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612e36573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e5a91906166e1565b612ec0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610ca6565b5f80612ecc8686614b25565b915091505f612edf836001015160c01c90565b5f81815260a160205260409020549091508214612f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b612f61816142a6565b612fc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610ca6565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161303e91616602565b116130e8575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526130e391839173ffffffffffffffffffffffffffffffffffffffff1690615932565b612b47565b6130f38386866155a6565b612b4781336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615ab8565b61313b614aa4565b60aa80545f90915561314d8282615b9e565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101612000565b6131a1614aa4565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415613232576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610ca6565b5f8061323e8484614b25565b915091505f613251836001015160c01c90565b905080156132bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610ca6565b5f6132c7846079015190565b905080613330576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610ca6565b600984015160c01c1561339f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610ca6565b5f6133ab856019015190565b03613412576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610ca6565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461343e856039015190565b146134a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610ca6565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f806135df8686614b25565b915091505f6135f2836001015160c01c90565b5f81815260a16020526040902054909150821461366b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b612b478386866155a6565b61367e614aa4565b80156137d75761368c615c6a565b60a65460ff16156137895760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a590925282208054919290916136ed908490616602565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b6137df615cef565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336137ac565b50565b613811614aa4565b5f81118015613822575060ac548114155b613888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610ca6565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101612000565b335f908152609f602052604090205460ff1661393e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610ca6565b60a854156139a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b6139b0614cdb565b60a65460ff1615613a1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610ca6565b8167ffffffffffffffff16609d5410613a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a160205260409020548114613b13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610ca6565b613b268267ffffffffffffffff16611bec565b613b8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613c2e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610ca6565b67ffffffffffffffff82165f90815260a260205260409020600101544210613cd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610ca6565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d42573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d669190616628565b341015613dcf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610ca6565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613f3b91815260200190565b60405180910390a35f609d546001613f539190616602565b90505b609e548111613fab578267ffffffffffffffff168114613f99576099545f82815260a2602052604081206001018054909190613f93908490616602565b90915550505b80613fa3816166fc565b915050613f56565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff16158015613ffb57505f5460ff8083169116105b614087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556140bf614aa4565b815f03614128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610ca6565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b335f90815260a5602052604081205490819003614239576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610ca6565b335f90815260a560205260408120556142528282615b9e565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161429a91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611c145750505f90815260a46020526040902060030154610100900460ff161590565b614305614aa4565b5f8111801561431657506098548114155b61437c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610ca6565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101612000565b6143c2614aa4565b73ffffffffffffffffffffffffffffffffffffffff8116614465576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ca6565b61380681615780565b5f54600490610100900460ff1615801561448e57505f5460ff8083169116105b61451a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ca6565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff831617610100179055614552614aa4565b73ffffffffffffffffffffffffffffffffffffffff82161580159061458d57505f8273ffffffffffffffffffffffffffffffffffffffff163b115b6145f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610ca6565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbfa02ba9000000000000000000000000000000000000000000000000000000001790525f90614657908490615d46565b905060a081901c156146c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020656e636f64696e670000000000000000006044820152606401610ca6565b6040515f602482018190528291614756908690604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9f8a13d700000000000000000000000000000000000000000000000000000000179052615d46565b6040805160048152602481019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d13fd7b000000000000000000000000000000000000000000000000000000001790529091505f906147bd908790615d46565b905073ffffffffffffffffffffffffffffffffffffffff8316301461483e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f7375626d697474657220726f6c6c7570206d69736d61746368000000000000006044820152606401610ca6565b8115801561484b57505f81115b6148b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c6964207375626d69747465722073746174650000000000000000006044820152606401610ca6565b609d54609e541461491e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610ca6565b60a85415614988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610ca6565b609d545f90815260a2602052604080822060030180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055609754905173ffffffffffffffffffffffffffffffffffffffff898116939216917fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f93991a35050609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861617905550505f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001612000565b60335473ffffffffffffffffffffffffffffffffffffffff163314612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca6565b5f805f614b328585615de9565b90505f8160ff165f03614b5357614b498686615e73565b9094509050614bd9565b8160ff1660011480614b6857508160ff166002145b15614b7757614b498686615ef6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610ca6565b808420925050509250929050565b5f81815260a2602052604090206003015473ffffffffffffffffffffffffffffffffffffffff1680614c17575050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260ae602052604090205480614ca3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f70656e64696e6720626174636820636f756e7420756e646572666c6f770000006044820152606401610ca6565b614cae600182616615565b73ffffffffffffffffffffffffffffffffffffffff9092165f90815260ae60205260409020919091555050565b60655460ff1615612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610ca6565b805f03614d53575050565b8082035f5b82811015614e0c57610100818403811115614d7257508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b158015614de2575f80fd5b505af1158015614df4573d5f803e3d5ffd5b50505050610100830192505061010081019050614d58565b50505050565b5f81600203614ebb575f6040515f5b804980614e2e5750614e3d565b60208202830152600101614e21565b602081028083209201604052909250905080614eb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610ca6565b50919050565b60014915614f4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610ca6565b5f4915614f59575f49611c14565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002614f9060208501856166c1565b60ff161115614ffb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610ca6565b6080830135615066576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610ca6565b60a08301356150d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610ca6565b5f806150e36119ba6020870187616660565b915091505f6150f6836001015160c01c90565b90505f60a181615107846001616602565b81526020019081526020015f20541461517c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610ca6565b609e5481146151e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610ca6565b5f81815260a16020526040902054821461525d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610ca6565b5f81815260ab60205260409020546080870135146152d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610ca6565b5f6152e6846011015160c01c90565b90505f6153126152fc60608a0160408b01616733565b61530c60808b0160608c0161663f565b84615f63565b90506153246080890160608a0161663f565b60019384019361ffff91909116929092019160f99061534660208b018b6166c1565b60ff161061535357506101015b6040805182810190915295506153788661537060208c018c6166c1565b60ff16615fa7565b60c084901b60018701526153a68661539660808c0160608d0161663f565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d9860185905260016153f660208b018b6166c1565b60ff1610615428576154288661541260608c0160408d01616733565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156154915760a7545f90815260a46020526040902060020154609954429161548491616602565b61548e9190616615565b90505b604051806080016040528042815260200182609854426154b19190616602565b6154bb9190616602565b81526020016154d060608d0160408e01616733565b67ffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8b81166020928301525f88815260a28352604090819020845181559284015160018401558301516002830155606090920151600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190921617905561555c89615fae565b5050609e8390555f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a35050505050505050565b8061560d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610ca6565b5f61561c846001015160c01c90565b90505f61562a856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000615659876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a848615728885160f81c90565b858888866040518663ffffffff1660e01b815260040161574c95949392919061674c565b5f6040518083038186803b158015615762575f80fd5b505afa158015615774573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff1661588c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b612785616007565b5f54610100900460ff1661592a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b6127856160c7565b60a88390555f83815260a460205260408082205460975491517fc96be4cb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af11580156159c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906159ea9190616628565b5f86815260a46020526040902060010154909150615a09908290616602565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a590915281208054909190615a55908490616602565b9091555050604051615a689084906167af565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490615adc90846167db565b615ae691906167f2565b9050615af28183616615565b60aa5f828254615b029190616602565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a5602052604081208054839290615b3b908490616602565b9091555050604051615b4e9084906167af565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015611f43575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615bfa576040519150601f19603f3d011682016040523d82523d5f602084013e615bff565b606091505b5050905080612660576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610ca6565b615c72614cdb565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258615cc53390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b615cf7616166565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33615cc5565b5f805f805f855160208701885afa91503d905060208114821615615d6e5760205f803e5f5192505b818015615d7b5750806020145b615de1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964207375626d697474657220696e7465726661636500000000006044820152606401610ca6565b505092915050565b5f81615e51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610ca6565b82825f818110615e6357615e6361682a565b919091013560f81c949350505050565b5f8160f9811015615ee0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610ca6565b6040519150808483378082016040529250929050565b5f816101018114615ee0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610ca6565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101615f988161ffff8716866161d2565b82900390912095945050505050565b8082535050565b73ffffffffffffffffffffffffffffffffffffffff8116156138065773ffffffffffffffffffffffffffffffffffffffff81165f90815260ae60205260408120805460019290615fff908490616602565b909155505050565b5f54610100900460ff1661609d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff1661615d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ca6565b61278533615780565b60655460ff16612785576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610ca6565b5f825f036161e15750826162ae565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b848110156162a8576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa15801561626f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906162939190616628565b875250602090950194600193840193016161fc565b50849150505b9392505050565b5f602082840312156162c5575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614f7c575f80fd5b5f602082840312156162ff575f80fd5b6162ae826162cc565b5f8083601f840112616318575f80fd5b50813567ffffffffffffffff81111561632f575f80fd5b602083019150836020828501011115616346575f80fd5b9250929050565b5f805f6040848603121561635f575f80fd5b833567ffffffffffffffff811115616375575f80fd5b61638186828701616308565b909790965060209590950135949350505050565b5f80602083850312156163a6575f80fd5b823567ffffffffffffffff8111156163bc575f80fd5b6163c885828601616308565b90969095509350505050565b5f60e08284031215614eb5575f80fd5b5f805f805f606086880312156163f8575f80fd5b853567ffffffffffffffff8082111561640f575f80fd5b61641b89838a016163d4565b96506020880135915080821115616430575f80fd5b61643c89838a01616308565b90965094506040880135915080821115616454575f80fd5b5061646188828901616308565b969995985093965092949392505050565b5f60208284031215616482575f80fd5b813567ffffffffffffffff811115616498575f80fd5b6164a4848285016163d4565b949350505050565b5f805f805f8060c087890312156164c1575f80fd5b6164ca876162cc565b95506164d8602088016162cc565b94506164e6604088016162cc565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561651a575f80fd5b843567ffffffffffffffff80821115616531575f80fd5b61653d88838901616308565b90965094506020870135915080821115616555575f80fd5b5061656287828801616308565b95989497509550505050565b8015158114613806575f80fd5b5f6020828403121561658b575f80fd5b81356162ae8161656e565b803567ffffffffffffffff81168114614f7c575f80fd5b5f80604083850312156165be575f80fd5b6165c783616596565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611c1457611c146165d5565b81810381811115611c1457611c146165d5565b5f60208284031215616638575f80fd5b5051919050565b5f6020828403121561664f575f80fd5b813561ffff811681146162ae575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112616693575f80fd5b83018035915067ffffffffffffffff8211156166ad575f80fd5b602001915036819003821315616346575f80fd5b5f602082840312156166d1575f80fd5b813560ff811681146162ae575f80fd5b5f602082840312156166f1575f80fd5b81516162ae8161656e565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361672c5761672c6165d5565b5060010190565b5f60208284031215616743575f80fd5b6162ae82616596565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156167ce57602081860181015185830152016167b4565b505f920191825250919050565b8082028115828204841417611c1457611c146165d5565b5f82616825577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a" +var RollupDeployedBin = "0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610b1f578063e3fff1dd14610b34578063f2fde38b14610b53578063fb1e8b0414610b72575f80fd5b8063d8dc99d214610abf578063ddd8a3dc14610ad4578063de8b303514610b00575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a59578063ce5db8d614610a6c578063cf9a674514610a81578063d279c19114610aa0575f80fd5b8063b8d0a1b0146109fc578063bedb86fb14610a1b578063c555389214610a3a575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461098a578063b34844251461099f578063b35dac4e146109be578063b3e0a509146109dd575f80fd5b8063a479265d1461092b578063a4f209b014610940578063abc8d68d1461095f575f80fd5b80638f1d3776116101985780638f1d3776146107e3578063910129d4146108ad57806397fc007c146108de578063a415d8dc146108fd575f80fd5b8063728cdbca1461078157806388b1ea09146107a05780638da5cb5b146107b9575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e578063612672901461070457806368589dfa146107235780636c578c1d1461074e578063715018a61461076d575f80fd5b80635c975abb146106415780635ef7a94a146106585780635f77cf1d146106b8575f80fd5b80633e001b661161026e5780633e001b66146105db578063428868b5146105f05780634e8f1d671461060357806357e0af6c14610622575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a146105af575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004615c9f565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004615cd9565b610b87565b005b3480156103f0575f80fd5b506103e36103ff366004615d37565b610cab565b34801561040f575f80fd5b5061038c61041e366004615c9f565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004615d7f565b611097565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004615c9f565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004615dde565b6116b6565b3480156104c9575f80fd5b5061038c6104d8366004615c9f565b611b64565b3480156104e8575f80fd5b506103b66104f7366004615c9f565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004615c9f565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004615c9f565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610398565b3480156105ba575f80fd5b50609b5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105e6575f80fd5b506103b660aa5481565b6103e36105fe366004615dde565b611b92565b34801561060e575f80fd5b506103e361061d366004615e3e565b611fd6565b34801561062d575f80fd5b506103e361063c366004615c9f565b612440565b34801561064c575f80fd5b5060655460ff1661038c565b348015610663575f80fd5b50610698610672366004615c9f565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b3480156106c3575f80fd5b506106eb7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b34801561070f575f80fd5b506103e361071e366004615c9f565b612505565b34801561072e575f80fd5b506103b661073d366004615c9f565b60ab6020525f908152604090205481565b348015610759575f80fd5b506103e3610768366004615cd9565b612768565b348015610778575f80fd5b506103e3612877565b34801561078c575f80fd5b506103e361079b366004615eef565b61288a565b3480156107ab575f80fd5b5060a65461038c9060ff1681565b3480156107c4575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661058a565b3480156107ee575f80fd5b5061085c6107fd366004615c9f565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b3480156108b8575f80fd5b5061038c6108c7366004615c9f565b5f90815260a4602052604090206003015460ff1690565b3480156108e9575f80fd5b506103e36108f8366004615cd9565b612c53565b348015610908575f80fd5b5061038c610917366004615cd9565b609f6020525f908152604090205460ff1681565b348015610936575f80fd5b506103b660995481565b34801561094b575f80fd5b506103e361095a366004615c9f565b612d77565b34801561096a575f80fd5b506103b6610979366004615cd9565b60a56020525f908152604090205481565b348015610995575f80fd5b506103b660a85481565b3480156109aa575f80fd5b506103e36109b9366004615f4a565b612e41565b3480156109c9575f80fd5b506103e36109d8366004615cd9565b613220565b3480156109e8575f80fd5b506103e36109f7366004615d7f565b613286565b348015610a07575f80fd5b506103e3610a16366004615f4a565b61367f565b348015610a26575f80fd5b506103e3610a35366004615fbe565b613722565b348015610a45575f80fd5b506103e3610a54366004615c9f565b6138b5565b6103e3610a67366004615ff0565b613972565b348015610a77575f80fd5b506103b660985481565b348015610a8c575f80fd5b506103e3610a9b366004615c9f565b614087565b348015610aab575f80fd5b506103e3610aba366004615cd9565b614264565b348015610aca575f80fd5b506103b660ac5481565b348015610adf575f80fd5b5060975461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b0b575f80fd5b5061038c610b1a366004615c9f565b61434a565b348015610b2a575f80fd5b506103b6609a5481565b348015610b3f575f80fd5b506103e3610b4e366004615c9f565b6143a1565b348015610b5e575f80fd5b506103e3610b6d366004615cd9565b61445e565b348015610b7d575f80fd5b506103b660a95481565b610b8f614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610c23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610cb3614512565b5f8111610d1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c1a565b5f80610d288585614593565b915091505f610d3b836001015160c01c90565b5f81815260a160205260409020549091508214610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f60a181610dc28785616045565b81526020019081526020015f205414610e5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b609d548111610eed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b610ef8600182616058565b609e555b831561108f57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610f448161434a565b15610fca575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091610f9c908490616045565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a85415801590611047575060a85481145b15611051575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610efc575b505050505050565b60a85415611101576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611109614655565b5f806111158484614593565b915091505f611128836001015160c01c90565b5f81815260a1602052604090205490915082146111a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6111aa81611b64565b611210576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b6112198161434a565b15611280576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003015460ff16156112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c1a565b5f81815260a26020526040902060010154421015611375576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c1a565b605983015160a05f611388600185616058565b81526020019081526020015f2054146113fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f81815260a0602052604090205415611472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c1a565b80609d54600101146114e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b609d819055600160a35f6114f5866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a06020526040902055611562611555846011015160c01c90565b600985015160c01c6146c2565b60a25f611570600184616058565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab91906115a99084616058565b81526020019081526020015f205f905560ad5f6001836115c99190616058565b81526020019081526020015f205f905560a45f6001836115e99190616058565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611692866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa15801561173c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611760919061606b565b6117c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611838614655565b5f49156118a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c1a565b5f6118b76118b26020850185616086565b614593565b5090505f6118c9826001015160c01c90565b6118d4906001616045565b5f81815260ad6020526040902054909150611971576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa1580156119e2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a0691906160e7565b611a109190616045565b1015611a92575f611a2760808601606087016160fe565b61ffff1611611a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b3e91906160e7565b9050611b5d85858360ad5f8781526020019081526020015f205461478c565b5050505050565b5f81815260a2602052604081205415801590611b8c57505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611c18573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c3c919061606b565b611ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611d14614655565b5f611d256118b26020850185616086565b5090505f611d37826001015160c01c90565b611d42906001616045565b5f81815260ad602052604090205490915015611de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7591906160e7565b611e7f9190616045565b1015611f01575f611e9660808601606087016160fe565b61ffff1611611f01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611f89573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fad91906160e7565b90505f611fc8611fc0602088018861611f565b60ff16614ec9565b905061108f8686848461478c565b60a85415612040576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612048614655565b60ac54609e545f90815260a260205260408120549091429161206a9190616045565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120dc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210091906160e7565b61210a9190616045565b109050811580156121185750805b15612199575f61212e60808a0160608b016160fe565b61ffff1611612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b81806121a25750805b612208576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c1a565b5f6122196118b260208b018b616086565b5090505f61222b826001015160c01c90565b612236906001616045565b5f81815260ad602052604081205491925090156122f0575f49156122dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c1a565b505f81815260ad6020526040902054612303565b612300611fc060208d018d61611f565b90505b61230f8b8b5f8461478c565b5f8061231b8b8b614593565b915091505f61232e836001015160c01c90565b905080609e541461239b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214612411576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f81815260a26020526040902042600190910155612430838b8b615038565b5050505050505050505050505050565b612448614512565b5f8111801561245957506099548114155b6124bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c1a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561252557505f5460ff8083169116105b6125b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556125ec5f5460ff1690565b60ff16600214612658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c1a565b816126e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c1a565b609e545f90815260ab602052604090205461270e57609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b612770614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff166127fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c1a565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610ca0565b61287f614512565b6128885f615212565b565b5f54610100900460ff16158080156128a857505f54600160ff909116105b806128c15750303b1580156128c157505f5460ff166001145b61294d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156129a9575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806129e0575073ffffffffffffffffffffffffffffffffffffffff8516155b15612a17576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8716612a94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610c1a565b612a9c615288565b612aa4615326565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612c4a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612c5b614512565b73ffffffffffffffffffffffffffffffffffffffff811615801590612c9b5750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612d01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c1a565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612d7f614512565b5f81118015612d8f575060648111155b8015612d9d575060a9548114155b612e03576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c1a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b022391016124f9565b60a85415612eab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612eb3614655565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612f39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5d919061606b565b612fc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b5f80612fcf8686614593565b915091505f612fe2836001015160c01c90565b5f81815260a16020526040902054909150821461305b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6130648161434a565b6130ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161314191616045565b116131d5575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526131d0918391906153c4565b612c4a565b6131e0838686615038565b612c4a81336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615547565b613228614512565b60aa80545f90915561323a828261562d565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d8791016124f9565b61328e614512565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea541561331f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c1a565b5f8061332b8484614593565b915091505f61333e836001015160c01c90565b905080156133a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c1a565b5f6133b4846079015190565b90508061341d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c1a565b600984015160c01c1561348c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c1a565b5f613498856019015190565b036134ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c1a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461352b856039015190565b14613592576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c1a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061368b8686614593565b915091505f61369e836001015160c01c90565b5f81815260a160205260409020549091508214613717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b612c4a838686615038565b61372a614512565b8015613883576137386156ff565b60a65460ff16156138355760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091613799908490616045565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b61388b615784565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613858565b50565b6138bd614512565b5f811180156138ce575060ac548114155b613934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c1a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad191016124f9565b335f908152609f602052604090205460ff166139ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c1a565b60a85415613a54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b613a5c614655565b60a65460ff1615613ac9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c1a565b8167ffffffffffffffff16609d5410613b3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a160205260409020548114613bbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b613bd28267ffffffffffffffff16611b64565b613c38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613cda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a260205260409020600101544210613d84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c1a565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dee573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1291906160e7565b341015613e7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613fe791815260200190565b60405180910390a35f609d546001613fff9190616045565b90505b609e548111614057578267ffffffffffffffff168114614045576099545f82815260a260205260408120600101805490919061403f908490616045565b90915550505b8061404f8161613f565b915050614002565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff161580156140a757505f5460ff8083169116105b614133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001781558290036141cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c1a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b335f90815260a56020526040812054908190036142dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c1a565b335f90815260a560205260408120556142f6828261562d565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161433e91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611b8c5750505f90815260a46020526040902060030154610100900460ff161590565b6143a9614512565b5f811180156143ba57506098548114155b614420576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c1a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a43791016124f9565b614466614512565b73ffffffffffffffffffffffffffffffffffffffff8116614509576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c1a565b6138b281615212565b60335473ffffffffffffffffffffffffffffffffffffffff163314612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c1a565b5f805f6145a085856157db565b90505f8160ff165f036145c1576145b78686615865565b9094509050614647565b8160ff16600114806145d657508160ff166002145b156145e5576145b786866158e8565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c1a565b808420925050509250929050565b60655460ff1615612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c1a565b805f036146cd575050565b8082035f5b82811015614786576101008184038111156146ec57508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b15801561475c575f80fd5b505af115801561476e573d5f803e3d5ffd5b505050506101008301925050610100810190506146d2565b50505050565b600261479b602086018661611f565b60ff161115614806576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c1a565b6080840135614871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c1a565b60a08401356148dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c1a565b5f806148ee6118b26020880188616086565b915091505f614901836001015160c01c90565b90505f60a181614912846001616045565b81526020019081526020015f205414614987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c1a565b609e5481146149f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214614a68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c1a565b5f81815260ab6020526040902054608088013514614ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f614af1846011015160c01c90565b90505f614b1d614b0760608b0160408c01616176565b614b1760808c0160608d016160fe565b84615955565b9050614b2f60808a0160608b016160fe565b60019384019361ffff91909116929092019160f990614b5160208c018c61611f565b60ff1610614b5e57506101015b604080518281019091529550614b8386614b7b60208d018d61611f565b60ff16615999565b60c084901b6001870152614bb186614ba160808d0160608e016160fe565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152614c1586614bf660208c018c616086565b604051614c0492919061618f565b604051809103902060b99190910152565b60d986018590526001614c2b60208c018c61611f565b60ff1610614c5d57614c5d86614c4760608d0160408e01616176565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff1615614cc65760a7545f90815260a460205260409020600201546099544291614cb991616045565b614cc39190616058565b90505b60405180608001604052804281526020018260985442614ce69190616045565b614cf09190616045565b8152602001614d0560608e0160408f01616176565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e86905560975473ffffffffffffffffffffffffffffffffffffffff1692506374fe27b791508a3590614d8c90614d86908d018d616086565b5f6159a0565b5f614d9a60408e018e616086565b6040518663ffffffff1660e01b8152600401614dba9594939291906161e5565b602060405180830381865afa158015614dd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df9919061606b565b614e85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f81600203614f72575f6040515f5b804980614ee55750614ef4565b60208202830152600101614ed8565b602081028083209201604052909250905080614f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c1a565b50919050565b60014915615002576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f4915615010575f49611b8c565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b8061509f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c1a565b5f6150ae846001015160c01c90565b90505f6150bc856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006150eb876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a8486151ba885160f81c90565b858888866040518663ffffffff1660e01b81526004016151de959493929190616265565b5f6040518083038186803b1580156151f4575f80fd5b505afa158015615206573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff1661531e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b6128886159f4565b5f54610100900460ff166153bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b612888615ab4565b60a88390555f83815260a460205260408082205460975491517f45bc4d10000000000000000000000000000000000000000000000000000000008152600481018690526801000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116939216906345bc4d10906024016020604051808303815f875af1158015615455573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061547991906160e7565b5f86815260a46020526040902060010154909150615498908290616045565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a5909152812080549091906154e4908490616045565b90915550506040516154f7908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061556b90846162c2565b61557591906162d9565b90506155818183616058565b60aa5f8282546155919190616045565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a56020526040812080548392906155ca908490616045565b90915550506040516155dd908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b80156156fb575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615689576040519150601f19603f3d011682016040523d82523d5f602084013e61568e565b606091505b50509050806156f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c1a565b505b5050565b615707614655565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861575a3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b61578c615b53565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361575a565b5f81615843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c1a565b82825f81811061585557615855616311565b919091013560f81c949350505050565b5f8160f98110156158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c1a565b6040519150808483378082016040529250929050565b5f8161010181146158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c1a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f91810161598a8161ffff871686615bbf565b82900390912095945050505050565b8082535050565b60605f808080806159b3888a018a61642b565b95509550955095509550508187106159d15794506159ed9350505050565b8387106159e55782955050505050506159ed565b509293505050505b9392505050565b5f54610100900460ff16615a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff16615b4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b61288833615212565b60655460ff16612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c1a565b5f825f03615bce5750826159ed565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b84811015615c95576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa158015615c5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190615c8091906160e7565b87525060209095019460019384019301615be9565b5093949350505050565b5f60208284031215615caf575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114615033575f80fd5b5f60208284031215615ce9575f80fd5b6159ed82615cb6565b5f8083601f840112615d02575f80fd5b50813567ffffffffffffffff811115615d19575f80fd5b602083019150836020828501011115615d30575f80fd5b9250929050565b5f805f60408486031215615d49575f80fd5b833567ffffffffffffffff811115615d5f575f80fd5b615d6b86828701615cf2565b909790965060209590950135949350505050565b5f8060208385031215615d90575f80fd5b823567ffffffffffffffff811115615da6575f80fd5b615db285828601615cf2565b90969095509350505050565b5f60e08284031215614f6c575f80fd5b5f60608284031215614f6c575f80fd5b5f8060408385031215615def575f80fd5b823567ffffffffffffffff80821115615e06575f80fd5b615e1286838701615dbe565b93506020850135915080821115615e27575f80fd5b50615e3485828601615dce565b9150509250929050565b5f805f805f8060808789031215615e53575f80fd5b863567ffffffffffffffff80821115615e6a575f80fd5b615e768a838b01615dbe565b97506020890135915080821115615e8b575f80fd5b615e978a838b01615dce565b96506040890135915080821115615eac575f80fd5b615eb88a838b01615cf2565b90965094506060890135915080821115615ed0575f80fd5b50615edd89828a01615cf2565b979a9699509497509295939492505050565b5f805f805f8060c08789031215615f04575f80fd5b615f0d87615cb6565b9550615f1b60208801615cb6565b9450615f2960408801615cb6565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f8060408587031215615f5d575f80fd5b843567ffffffffffffffff80821115615f74575f80fd5b615f8088838901615cf2565b90965094506020870135915080821115615f98575f80fd5b50615fa587828801615cf2565b95989497509550505050565b80151581146138b2575f80fd5b5f60208284031215615fce575f80fd5b81356159ed81615fb1565b803567ffffffffffffffff81168114615033575f80fd5b5f8060408385031215616001575f80fd5b61600a83615fd9565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611b8c57611b8c616018565b81810381811115611b8c57611b8c616018565b5f6020828403121561607b575f80fd5b81516159ed81615fb1565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126160b9575f80fd5b83018035915067ffffffffffffffff8211156160d3575f80fd5b602001915036819003821315615d30575f80fd5b5f602082840312156160f7575f80fd5b5051919050565b5f6020828403121561610e575f80fd5b813561ffff811681146159ed575f80fd5b5f6020828403121561612f575f80fd5b813560ff811681146159ed575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361616f5761616f616018565b5060010190565b5f60208284031215616186575f80fd5b6159ed82615fd9565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b8181101561623c57845173ffffffffffffffffffffffffffffffffffffffff168352938301939183019160010161620a565b5050876040860152848103606086015261625781878961619e565b9a9950505050505050505050565b858152846020820152608060408201525f61628460808301858761619e565b90508260608301529695505050505050565b5f82515f5b818110156162b5576020818601810151858301520161629b565b505f920191825250919050565b8082028115828204841417611b8c57611b8c616018565b5f8261630c577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261637a575f80fd5b8135602067ffffffffffffffff808311156163975761639761633e565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156163da576163da61633e565b60405293845260208187018101949081019250878511156163f9575f80fd5b6020870191505b848210156164205761641182615cb6565b83529183019190830190616400565b979650505050505050565b5f805f805f8060c08789031215616440575f80fd5b86359550602087013567ffffffffffffffff8082111561645e575f80fd5b61646a8a838b0161636b565b9650604089013595506060890135915080821115616486575f80fd5b6164928a838b0161636b565b94506080890135935060a08901359150808211156164ae575f80fd5b506164bb89828a0161636b565b915050929550929550929556fea164736f6c6343000818000a" func init() { if err := json.Unmarshal([]byte(RollupStorageLayoutJSON), RollupStorageLayout); err != nil { diff --git a/bindings/bindings/submitter.go b/bindings/bindings/submitter.go deleted file mode 100644 index 9361dc2f0..000000000 --- a/bindings/bindings/submitter.go +++ /dev/null @@ -1,2863 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// SubmitterMetaData contains all meta data concerning the Submitter contract. -var SubmitterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"CreditClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"MinimumStakeUpdated\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalCredit\",\"type\":\"uint256\"}],\"name\":\"WithdrawalCredited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"addSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimCredit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"claimable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"exiting\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isExiting\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rollupContract_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardPercentage_\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"isActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"registered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"removeSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setMinimumStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"stakeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561000f575f80fd5b5061001861001d565b6100d9565b5f54610100900460ff16156100885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100d7575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611df9806100e65f395ff3fe60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd111461044a578063d13f90b414610469578063ec5ffac214610488578063f2fde38b1461049d575f80fd5b8063bfa02ba9146103ed578063c36f41e21461040c578063c96be4cb1461042b575f80fd5b8063ab8c53dc116100b7578063ab8c53dc1461037c578063b2dd5c0714610391578063bbfefd38146103bf575f80fd5b80639f8a13d71461030f578063a3066aab1461033e578063a4f209b01461035d575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac366004611cca565b6104bc565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f5366004611cea565b6105b4565b348015610205575f80fd5b506101b1610214366004611cea565b61065a565b6101b1610700565b34801561022c575f80fd5b506101c861023b366004611cca565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c8610266366004611cca565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b1610291366004611cca565b61086e565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c5366004611cca565b610a06565b3480156102d5575f80fd5b506101b1610b45565b3480156102e9575f80fd5b506033546001600160a01b03165b6040516001600160a01b0390911681526020016101d2565b34801561031a575f80fd5b5061032e610329366004611cca565b610b56565b60405190151581526020016101d2565b348015610349575f80fd5b506101b1610358366004611cca565b610bc0565b348015610368575f80fd5b506101b1610377366004611cea565b610ce5565b348015610387575f80fd5b506101c8609b5481565b34801561039c575f80fd5b5061032e6103ab366004611cca565b609c6020525f908152604090205460ff1681565b3480156103ca575f80fd5b5061032e6103d9366004611cca565b609e6020525f908152604090205460ff1681565b3480156103f8575f80fd5b506097546102f7906001600160a01b031681565b348015610417575f80fd5b506101b1610426366004611cca565b610d98565b348015610436575f80fd5b506101c8610445366004611cca565b610ef8565b348015610455575f80fd5b506101b1610464366004611cca565b611064565b348015610474575f80fd5b506101b1610483366004611d01565b611176565b348015610493575f80fd5b506101c860985481565b3480156104a8575f80fd5b506101b16104b7366004611cca565b61158a565b6104c4611617565b6001600160a01b038116158015906104f457506001600160a01b0381165f908152609c602052604090205460ff16155b801561051857506001600160a01b0381165f908152609e602052604090205460ff16155b6105695760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105bc611617565b5f811180156105cd57506098548114155b6106195760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610662611617565b5f8111801561067357506099548114155b6106bf5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610708611671565b335f818152609c602052604090205460ff16801561073e57506001600160a01b0381165f908152609e602052604090205460ff16155b61078a5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609d60205260408120546107ad903490611d77565b90505f341180156107c057506098548110155b61080c5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610560565b6001600160a01b0382165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061086c6001606555565b565b610876611671565b336001600160a01b0382166108cd5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609c602052604090205460ff16801561090c57506001600160a01b0381165f908152609e602052604090205460ff16155b801561092e57506001600160a01b0381165f908152609d602052604090205415155b61097a5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610560565b6001600160a01b038181165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a36109f881836116d1565b50610a036001606555565b50565b610a0e611671565b336001600160a01b038216610a655760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609f602052604090205480610aca5760405162461bcd60e51b815260206004820152600960248201527f6e6f2063726564697400000000000000000000000000000000000000000000006044820152606401610560565b6001600160a01b0382165f908152609f6020526040812055610aec83826116ed565b826001600160a01b0316826001600160a01b03167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610b3191815260200190565b60405180910390a35050610a036001606555565b610b4d611617565b61086c5f61179c565b6001600160a01b0381165f908152609c602052604081205460ff168015610b9557506001600160a01b0382165f908152609e602052604090205460ff16155b8015610bba57506098546001600160a01b0383165f908152609d602052604090205410155b92915050565b610bc8611671565b336001600160a01b038216610c1f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f908152609e602052604090205460ff16610c865760405162461bcd60e51b815260206004820152600b60248201527f6e6f742065786974696e670000000000000000000000000000000000000000006044820152606401610560565b610c8f81611805565b610cdb5760405162461bcd60e51b815260206004820152601760248201527f70656e64696e67206261746368206c696162696c6974790000000000000000006044820152606401610560565b6109f881836118f0565b610ced611617565b5f81118015610cfd575060648111155b8015610d0b5750609a548114155b610d575760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610da0611617565b610da8611671565b6001600160a01b0381165f908152609c602052604090205460ff168015610de757506001600160a01b0381165f908152609e602052604090205460ff16155b610e335760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610560565b6001600160a01b0381165f818152609c60209081526040808320805460ff19908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a26001600160a01b0381165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b3291610edc91815260200190565b60405180910390a3610eee81826116d1565b610a036001606555565b6097545f906001600160a01b0316336001600160a01b031614610f5d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610560565b610f65611671565b6001600160a01b038216610f7a57505f611055565b6001600160a01b0382165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216600117909155609a54606490610fce9083611d8a565b610fd89190611da1565b9150610fe48282611dd9565b609b5f828254610ff49190611d77565b909155505060975461100f906001600160a01b0316836116ed565b60408051828152602081018490526001600160a01b038516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61105f6001606555565b919050565b61106c611617565b611074611671565b6001600160a01b0381166110ca5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610560565b609b548061111a5760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610560565b5f609b5561112882826116ed565b816001600160a01b03167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161116391815260200190565b60405180910390a250610a036001606555565b5f54610100900460ff161580801561119457505f54600160ff909116105b806111ad5750303b1580156111ad57505f5460ff166001145b61121f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610560565b5f805460ff19166001179055801561125d575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0386166112b35760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610560565b6001600160a01b038516158015906112d457505f856001600160a01b03163b115b6113205760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610560565b5f841161136f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610560565b5f83116113be5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610560565b5f821180156113ce575060648211155b61141a5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610560565b611422611aab565b61142a611b2f565b6114338661179c565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611582575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611592611617565b6001600160a01b03811661160e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610560565b610a038161179c565b6033546001600160a01b0316331461086c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610560565b6002606554036116c35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610560565b6002606555565b6001606555565b6116da82611805565b156116e9576116e982826118f0565b5050565b805f036116f8575050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611741576040519150601f19603f3d011682016040523d82523d5f602084013e611746565b606091505b50509050806117975760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610560565b505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6040516001600160a01b03821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a80000000000000000000000000000000000000000000000000000000017815260975482519293506001600160a01b0316915f9182918291829182918761c350fa92503d9150602082148316156118ce5760205f803e505f515b8280156118db5750816020145b80156118e5575080155b979650505050505050565b6001600160a01b0382165f908152609d60209081526040808320805490849055609e9092528220805460ff191690559081900361197957816001600160a01b0316836001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f60405161196c91815260200190565b60405180910390a3505050565b5f826001600160a01b03168261c350906040515f60405180830381858888f193505050503d805f81146119c7576040519150601f19603f3d011682016040523d82523d5f602084013e6119cc565b606091505b505090508015611a2857826001600160a01b0316846001600160a01b03167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f4684604051611a1b91815260200190565b60405180910390a3611aa5565b6001600160a01b0384165f908152609f602052604081208054849290611a4f908490611d77565b90915550506001600160a01b0384165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff16611b275760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611bb3565b5f54610100900460ff16611bab5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c611c38565b5f54610100900460ff16611c2f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b61086c3361179c565b5f54610100900460ff166116ca5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610560565b80356001600160a01b038116811461105f575f80fd5b5f60208284031215611cda575f80fd5b611ce382611cb4565b9392505050565b5f60208284031215611cfa575f80fd5b5035919050565b5f805f805f60a08688031215611d15575f80fd5b611d1e86611cb4565b9450611d2c60208701611cb4565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610bba57610bba611d4a565b8082028115828204841417610bba57610bba611d4a565b5f82611dd4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610bba57610bba611d4a56fea164736f6c6343000818000a", -} - -// SubmitterABI is the input ABI used to generate the binding from. -// Deprecated: Use SubmitterMetaData.ABI instead. -var SubmitterABI = SubmitterMetaData.ABI - -// SubmitterBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use SubmitterMetaData.Bin instead. -var SubmitterBin = SubmitterMetaData.Bin - -// DeploySubmitter deploys a new Ethereum contract, binding an instance of Submitter to it. -func DeploySubmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Submitter, error) { - parsed, err := SubmitterMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SubmitterBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil -} - -// Submitter is an auto generated Go binding around an Ethereum contract. -type Submitter struct { - SubmitterCaller // Read-only binding to the contract - SubmitterTransactor // Write-only binding to the contract - SubmitterFilterer // Log filterer for contract events -} - -// SubmitterCaller is an auto generated read-only Go binding around an Ethereum contract. -type SubmitterCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SubmitterTransactor is an auto generated write-only Go binding around an Ethereum contract. -type SubmitterTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SubmitterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type SubmitterFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SubmitterSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type SubmitterSession struct { - Contract *Submitter // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// SubmitterCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type SubmitterCallerSession struct { - Contract *SubmitterCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// SubmitterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type SubmitterTransactorSession struct { - Contract *SubmitterTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// SubmitterRaw is an auto generated low-level Go binding around an Ethereum contract. -type SubmitterRaw struct { - Contract *Submitter // Generic contract binding to access the raw methods on -} - -// SubmitterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type SubmitterCallerRaw struct { - Contract *SubmitterCaller // Generic read-only contract binding to access the raw methods on -} - -// SubmitterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type SubmitterTransactorRaw struct { - Contract *SubmitterTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewSubmitter creates a new instance of Submitter, bound to a specific deployed contract. -func NewSubmitter(address common.Address, backend bind.ContractBackend) (*Submitter, error) { - contract, err := bindSubmitter(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil -} - -// NewSubmitterCaller creates a new read-only instance of Submitter, bound to a specific deployed contract. -func NewSubmitterCaller(address common.Address, caller bind.ContractCaller) (*SubmitterCaller, error) { - contract, err := bindSubmitter(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &SubmitterCaller{contract: contract}, nil -} - -// NewSubmitterTransactor creates a new write-only instance of Submitter, bound to a specific deployed contract. -func NewSubmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*SubmitterTransactor, error) { - contract, err := bindSubmitter(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &SubmitterTransactor{contract: contract}, nil -} - -// NewSubmitterFilterer creates a new log filterer instance of Submitter, bound to a specific deployed contract. -func NewSubmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*SubmitterFilterer, error) { - contract, err := bindSubmitter(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &SubmitterFilterer{contract: contract}, nil -} - -// bindSubmitter binds a generic wrapper to an already deployed contract. -func bindSubmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := SubmitterMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Submitter *SubmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Submitter.Contract.SubmitterCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Submitter *SubmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Submitter.Contract.SubmitterTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Submitter *SubmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Submitter.Contract.SubmitterTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Submitter *SubmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Submitter.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Submitter *SubmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Submitter.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Submitter *SubmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Submitter.Contract.contract.Transact(opts, method, params...) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_Submitter *SubmitterCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "challengeDeposit") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_Submitter *SubmitterSession) ChallengeDeposit() (*big.Int, error) { - return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_Submitter *SubmitterCallerSession) ChallengeDeposit() (*big.Int, error) { - return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) -} - -// Claimable is a free data retrieval call binding the contract method 0x402914f5. -// -// Solidity: function claimable(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterCaller) Claimable(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "claimable", submitter) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Claimable is a free data retrieval call binding the contract method 0x402914f5. -// -// Solidity: function claimable(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterSession) Claimable(submitter common.Address) (*big.Int, error) { - return _Submitter.Contract.Claimable(&_Submitter.CallOpts, submitter) -} - -// Claimable is a free data retrieval call binding the contract method 0x402914f5. -// -// Solidity: function claimable(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterCallerSession) Claimable(submitter common.Address) (*big.Int, error) { - return _Submitter.Contract.Claimable(&_Submitter.CallOpts, submitter) -} - -// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. -// -// Solidity: function exiting(address submitter) view returns(bool isExiting) -func (_Submitter *SubmitterCaller) Exiting(opts *bind.CallOpts, submitter common.Address) (bool, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "exiting", submitter) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. -// -// Solidity: function exiting(address submitter) view returns(bool isExiting) -func (_Submitter *SubmitterSession) Exiting(submitter common.Address) (bool, error) { - return _Submitter.Contract.Exiting(&_Submitter.CallOpts, submitter) -} - -// Exiting is a free data retrieval call binding the contract method 0xbbfefd38. -// -// Solidity: function exiting(address submitter) view returns(bool isExiting) -func (_Submitter *SubmitterCallerSession) Exiting(submitter common.Address) (bool, error) { - return _Submitter.Contract.Exiting(&_Submitter.CallOpts, submitter) -} - -// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. -// -// Solidity: function isActive(address submitter) view returns(bool) -func (_Submitter *SubmitterCaller) IsActive(opts *bind.CallOpts, submitter common.Address) (bool, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "isActive", submitter) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. -// -// Solidity: function isActive(address submitter) view returns(bool) -func (_Submitter *SubmitterSession) IsActive(submitter common.Address) (bool, error) { - return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) -} - -// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. -// -// Solidity: function isActive(address submitter) view returns(bool) -func (_Submitter *SubmitterCallerSession) IsActive(submitter common.Address) (bool, error) { - return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) -} - -// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. -// -// Solidity: function minimumStake() view returns(uint256) -func (_Submitter *SubmitterCaller) MinimumStake(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "minimumStake") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. -// -// Solidity: function minimumStake() view returns(uint256) -func (_Submitter *SubmitterSession) MinimumStake() (*big.Int, error) { - return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) -} - -// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. -// -// Solidity: function minimumStake() view returns(uint256) -func (_Submitter *SubmitterCallerSession) MinimumStake() (*big.Int, error) { - return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_Submitter *SubmitterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_Submitter *SubmitterSession) Owner() (common.Address, error) { - return _Submitter.Contract.Owner(&_Submitter.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_Submitter *SubmitterCallerSession) Owner() (common.Address, error) { - return _Submitter.Contract.Owner(&_Submitter.CallOpts) -} - -// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. -// -// Solidity: function registered(address submitter) view returns(bool isRegistered) -func (_Submitter *SubmitterCaller) Registered(opts *bind.CallOpts, submitter common.Address) (bool, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "registered", submitter) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. -// -// Solidity: function registered(address submitter) view returns(bool isRegistered) -func (_Submitter *SubmitterSession) Registered(submitter common.Address) (bool, error) { - return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) -} - -// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. -// -// Solidity: function registered(address submitter) view returns(bool isRegistered) -func (_Submitter *SubmitterCallerSession) Registered(submitter common.Address) (bool, error) { - return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_Submitter *SubmitterCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "rewardPercentage") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_Submitter *SubmitterSession) RewardPercentage() (*big.Int, error) { - return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_Submitter *SubmitterCallerSession) RewardPercentage() (*big.Int, error) { - return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_Submitter *SubmitterCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "rollupContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_Submitter *SubmitterSession) RollupContract() (common.Address, error) { - return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_Submitter *SubmitterCallerSession) RollupContract() (common.Address, error) { - return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_Submitter *SubmitterCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "slashRemaining") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_Submitter *SubmitterSession) SlashRemaining() (*big.Int, error) { - return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_Submitter *SubmitterCallerSession) SlashRemaining() (*big.Int, error) { - return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) -} - -// StakeOf is a free data retrieval call binding the contract method 0x42623360. -// -// Solidity: function stakeOf(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterCaller) StakeOf(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { - var out []interface{} - err := _Submitter.contract.Call(opts, &out, "stakeOf", submitter) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StakeOf is a free data retrieval call binding the contract method 0x42623360. -// -// Solidity: function stakeOf(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterSession) StakeOf(submitter common.Address) (*big.Int, error) { - return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) -} - -// StakeOf is a free data retrieval call binding the contract method 0x42623360. -// -// Solidity: function stakeOf(address submitter) view returns(uint256 amount) -func (_Submitter *SubmitterCallerSession) StakeOf(submitter common.Address) (*big.Int, error) { - return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) -} - -// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. -// -// Solidity: function addSubmitter(address submitter) returns() -func (_Submitter *SubmitterTransactor) AddSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "addSubmitter", submitter) -} - -// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. -// -// Solidity: function addSubmitter(address submitter) returns() -func (_Submitter *SubmitterSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) -} - -// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. -// -// Solidity: function addSubmitter(address submitter) returns() -func (_Submitter *SubmitterTransactorSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address receiver) returns() -func (_Submitter *SubmitterTransactor) ClaimCredit(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "claimCredit", receiver) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address receiver) returns() -func (_Submitter *SubmitterSession) ClaimCredit(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimCredit(&_Submitter.TransactOpts, receiver) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address receiver) returns() -func (_Submitter *SubmitterTransactorSession) ClaimCredit(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimCredit(&_Submitter.TransactOpts, receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_Submitter *SubmitterTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "claimSlashRemaining", receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_Submitter *SubmitterSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_Submitter *SubmitterTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_Submitter *SubmitterTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "claimWithdrawal", receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_Submitter *SubmitterSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_Submitter *SubmitterTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) -} - -// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. -// -// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() -func (_Submitter *SubmitterTransactor) Initialize(opts *bind.TransactOpts, owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "initialize", owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) -} - -// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. -// -// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() -func (_Submitter *SubmitterSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) -} - -// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. -// -// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() -func (_Submitter *SubmitterTransactorSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) -} - -// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. -// -// Solidity: function removeSubmitter(address submitter) returns() -func (_Submitter *SubmitterTransactor) RemoveSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "removeSubmitter", submitter) -} - -// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. -// -// Solidity: function removeSubmitter(address submitter) returns() -func (_Submitter *SubmitterSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) -} - -// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. -// -// Solidity: function removeSubmitter(address submitter) returns() -func (_Submitter *SubmitterTransactorSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_Submitter *SubmitterTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "renounceOwnership") -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_Submitter *SubmitterSession) RenounceOwnership() (*types.Transaction, error) { - return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_Submitter *SubmitterTransactorSession) RenounceOwnership() (*types.Transaction, error) { - return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) -} - -// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. -// -// Solidity: function setMinimumStake(uint256 value) returns() -func (_Submitter *SubmitterTransactor) SetMinimumStake(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "setMinimumStake", value) -} - -// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. -// -// Solidity: function setMinimumStake(uint256 value) returns() -func (_Submitter *SubmitterSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) -} - -// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. -// -// Solidity: function setMinimumStake(uint256 value) returns() -func (_Submitter *SubmitterTransactorSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) -} - -// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. -// -// Solidity: function slash(address submitter) returns(uint256 reward) -func (_Submitter *SubmitterTransactor) Slash(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "slash", submitter) -} - -// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. -// -// Solidity: function slash(address submitter) returns(uint256 reward) -func (_Submitter *SubmitterSession) Slash(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) -} - -// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. -// -// Solidity: function slash(address submitter) returns(uint256 reward) -func (_Submitter *SubmitterTransactorSession) Slash(submitter common.Address) (*types.Transaction, error) { - return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) -} - -// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. -// -// Solidity: function stake() payable returns() -func (_Submitter *SubmitterTransactor) Stake(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "stake") -} - -// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. -// -// Solidity: function stake() payable returns() -func (_Submitter *SubmitterSession) Stake() (*types.Transaction, error) { - return _Submitter.Contract.Stake(&_Submitter.TransactOpts) -} - -// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. -// -// Solidity: function stake() payable returns() -func (_Submitter *SubmitterTransactorSession) Stake() (*types.Transaction, error) { - return _Submitter.Contract.Stake(&_Submitter.TransactOpts) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_Submitter *SubmitterTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "transferOwnership", newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_Submitter *SubmitterSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_Submitter *SubmitterTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 value) returns() -func (_Submitter *SubmitterTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "updateChallengeDeposit", value) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 value) returns() -func (_Submitter *SubmitterSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 value) returns() -func (_Submitter *SubmitterTransactorSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 value) returns() -func (_Submitter *SubmitterTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "updateRewardPercentage", value) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 value) returns() -func (_Submitter *SubmitterSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 value) returns() -func (_Submitter *SubmitterTransactorSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { - return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. -// -// Solidity: function withdraw(address receiver) returns() -func (_Submitter *SubmitterTransactor) Withdraw(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _Submitter.contract.Transact(opts, "withdraw", receiver) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. -// -// Solidity: function withdraw(address receiver) returns() -func (_Submitter *SubmitterSession) Withdraw(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts, receiver) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x51cff8d9. -// -// Solidity: function withdraw(address receiver) returns() -func (_Submitter *SubmitterTransactorSession) Withdraw(receiver common.Address) (*types.Transaction, error) { - return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts, receiver) -} - -// SubmitterChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the Submitter contract. -type SubmitterChallengeDepositUpdatedIterator struct { - Event *SubmitterChallengeDepositUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterChallengeDepositUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterChallengeDepositUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterChallengeDepositUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the Submitter contract. -type SubmitterChallengeDepositUpdated struct { - OldValue *big.Int - NewValue *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*SubmitterChallengeDepositUpdatedIterator, error) { - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return &SubmitterChallengeDepositUpdatedIterator{contract: _Submitter.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil -} - -// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterChallengeDepositUpdated) (event.Subscription, error) { - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterChallengeDepositUpdated) - if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) ParseChallengeDepositUpdated(log types.Log) (*SubmitterChallengeDepositUpdated, error) { - event := new(SubmitterChallengeDepositUpdated) - if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterCreditClaimedIterator is returned from FilterCreditClaimed and is used to iterate over the raw logs and unpacked data for CreditClaimed events raised by the Submitter contract. -type SubmitterCreditClaimedIterator struct { - Event *SubmitterCreditClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterCreditClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterCreditClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterCreditClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterCreditClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterCreditClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterCreditClaimed represents a CreditClaimed event raised by the Submitter contract. -type SubmitterCreditClaimed struct { - Submitter common.Address - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterCreditClaimed is a free log retrieval operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. -// -// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) FilterCreditClaimed(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterCreditClaimedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "CreditClaimed", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return &SubmitterCreditClaimedIterator{contract: _Submitter.contract, event: "CreditClaimed", logs: logs, sub: sub}, nil -} - -// WatchCreditClaimed is a free log subscription operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. -// -// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) WatchCreditClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterCreditClaimed, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "CreditClaimed", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterCreditClaimed) - if err := _Submitter.contract.UnpackLog(event, "CreditClaimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseCreditClaimed is a log parse operation binding the contract event 0xc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f5322. -// -// Solidity: event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) ParseCreditClaimed(log types.Log) (*SubmitterCreditClaimed, error) { - event := new(SubmitterCreditClaimed) - if err := _Submitter.contract.UnpackLog(event, "CreditClaimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Submitter contract. -type SubmitterInitializedIterator struct { - Event *SubmitterInitialized // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterInitializedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterInitializedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterInitializedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterInitialized represents a Initialized event raised by the Submitter contract. -type SubmitterInitialized struct { - Version uint8 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_Submitter *SubmitterFilterer) FilterInitialized(opts *bind.FilterOpts) (*SubmitterInitializedIterator, error) { - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return &SubmitterInitializedIterator{contract: _Submitter.contract, event: "Initialized", logs: logs, sub: sub}, nil -} - -// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_Submitter *SubmitterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *SubmitterInitialized) (event.Subscription, error) { - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterInitialized) - if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_Submitter *SubmitterFilterer) ParseInitialized(log types.Log) (*SubmitterInitialized, error) { - event := new(SubmitterInitialized) - if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterMinimumStakeUpdatedIterator is returned from FilterMinimumStakeUpdated and is used to iterate over the raw logs and unpacked data for MinimumStakeUpdated events raised by the Submitter contract. -type SubmitterMinimumStakeUpdatedIterator struct { - Event *SubmitterMinimumStakeUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterMinimumStakeUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterMinimumStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterMinimumStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterMinimumStakeUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterMinimumStakeUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterMinimumStakeUpdated represents a MinimumStakeUpdated event raised by the Submitter contract. -type SubmitterMinimumStakeUpdated struct { - OldValue *big.Int - NewValue *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterMinimumStakeUpdated is a free log retrieval operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. -// -// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) FilterMinimumStakeUpdated(opts *bind.FilterOpts) (*SubmitterMinimumStakeUpdatedIterator, error) { - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "MinimumStakeUpdated") - if err != nil { - return nil, err - } - return &SubmitterMinimumStakeUpdatedIterator{contract: _Submitter.contract, event: "MinimumStakeUpdated", logs: logs, sub: sub}, nil -} - -// WatchMinimumStakeUpdated is a free log subscription operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. -// -// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) WatchMinimumStakeUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterMinimumStakeUpdated) (event.Subscription, error) { - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "MinimumStakeUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterMinimumStakeUpdated) - if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseMinimumStakeUpdated is a log parse operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. -// -// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) ParseMinimumStakeUpdated(log types.Log) (*SubmitterMinimumStakeUpdated, error) { - event := new(SubmitterMinimumStakeUpdated) - if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Submitter contract. -type SubmitterOwnershipTransferredIterator struct { - Event *SubmitterOwnershipTransferred // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterOwnershipTransferredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterOwnershipTransferredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterOwnershipTransferred represents a OwnershipTransferred event raised by the Submitter contract. -type SubmitterOwnershipTransferred struct { - PreviousOwner common.Address - NewOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_Submitter *SubmitterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*SubmitterOwnershipTransferredIterator, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return &SubmitterOwnershipTransferredIterator{contract: _Submitter.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_Submitter *SubmitterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SubmitterOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterOwnershipTransferred) - if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_Submitter *SubmitterFilterer) ParseOwnershipTransferred(log types.Log) (*SubmitterOwnershipTransferred, error) { - event := new(SubmitterOwnershipTransferred) - if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the Submitter contract. -type SubmitterRewardPercentageUpdatedIterator struct { - Event *SubmitterRewardPercentageUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterRewardPercentageUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterRewardPercentageUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterRewardPercentageUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the Submitter contract. -type SubmitterRewardPercentageUpdated struct { - OldValue *big.Int - NewValue *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*SubmitterRewardPercentageUpdatedIterator, error) { - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return &SubmitterRewardPercentageUpdatedIterator{contract: _Submitter.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil -} - -// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterRewardPercentageUpdated) (event.Subscription, error) { - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterRewardPercentageUpdated) - if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) -func (_Submitter *SubmitterFilterer) ParseRewardPercentageUpdated(log types.Log) (*SubmitterRewardPercentageUpdated, error) { - event := new(SubmitterRewardPercentageUpdated) - if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the Submitter contract. -type SubmitterSlashRemainingClaimedIterator struct { - Event *SubmitterSlashRemainingClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterSlashRemainingClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterSlashRemainingClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterSlashRemainingClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the Submitter contract. -type SubmitterSlashRemainingClaimed struct { - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts, receiver []common.Address) (*SubmitterSlashRemainingClaimedIterator, error) { - - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "SlashRemainingClaimed", receiverRule) - if err != nil { - return nil, err - } - return &SubmitterSlashRemainingClaimedIterator{contract: _Submitter.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil -} - -// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashRemainingClaimed, receiver []common.Address) (event.Subscription, error) { - - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "SlashRemainingClaimed", receiverRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterSlashRemainingClaimed) - if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) ParseSlashRemainingClaimed(log types.Log) (*SubmitterSlashRemainingClaimed, error) { - event := new(SubmitterSlashRemainingClaimed) - if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the Submitter contract. -type SubmitterSlashedIterator struct { - Event *SubmitterSlashed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterSlashedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterSlashedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterSlashedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterSlashed represents a Slashed event raised by the Submitter contract. -type SubmitterSlashed struct { - Submitter common.Address - Amount *big.Int - Reward *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashed is a free log retrieval operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. -// -// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) -func (_Submitter *SubmitterFilterer) FilterSlashed(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSlashedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "Slashed", submitterRule) - if err != nil { - return nil, err - } - return &SubmitterSlashedIterator{contract: _Submitter.contract, event: "Slashed", logs: logs, sub: sub}, nil -} - -// WatchSlashed is a free log subscription operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. -// -// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) -func (_Submitter *SubmitterFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashed, submitter []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "Slashed", submitterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterSlashed) - if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashed is a log parse operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. -// -// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) -func (_Submitter *SubmitterFilterer) ParseSlashed(log types.Log) (*SubmitterSlashed, error) { - event := new(SubmitterSlashed) - if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterStakedIterator is returned from FilterStaked and is used to iterate over the raw logs and unpacked data for Staked events raised by the Submitter contract. -type SubmitterStakedIterator struct { - Event *SubmitterStaked // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterStakedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterStaked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterStaked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterStakedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterStakedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterStaked represents a Staked event raised by the Submitter contract. -type SubmitterStaked struct { - Submitter common.Address - Amount *big.Int - Total *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStaked is a free log retrieval operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. -// -// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) -func (_Submitter *SubmitterFilterer) FilterStaked(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterStakedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "Staked", submitterRule) - if err != nil { - return nil, err - } - return &SubmitterStakedIterator{contract: _Submitter.contract, event: "Staked", logs: logs, sub: sub}, nil -} - -// WatchStaked is a free log subscription operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. -// -// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) -func (_Submitter *SubmitterFilterer) WatchStaked(opts *bind.WatchOpts, sink chan<- *SubmitterStaked, submitter []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "Staked", submitterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterStaked) - if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStaked is a log parse operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. -// -// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) -func (_Submitter *SubmitterFilterer) ParseStaked(log types.Log) (*SubmitterStaked, error) { - event := new(SubmitterStaked) - if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterSubmitterAddedIterator is returned from FilterSubmitterAdded and is used to iterate over the raw logs and unpacked data for SubmitterAdded events raised by the Submitter contract. -type SubmitterSubmitterAddedIterator struct { - Event *SubmitterSubmitterAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterSubmitterAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterSubmitterAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterSubmitterAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterSubmitterAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterSubmitterAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterSubmitterAdded represents a SubmitterAdded event raised by the Submitter contract. -type SubmitterSubmitterAdded struct { - Submitter common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSubmitterAdded is a free log retrieval operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. -// -// Solidity: event SubmitterAdded(address indexed submitter) -func (_Submitter *SubmitterFilterer) FilterSubmitterAdded(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterAddedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterAdded", submitterRule) - if err != nil { - return nil, err - } - return &SubmitterSubmitterAddedIterator{contract: _Submitter.contract, event: "SubmitterAdded", logs: logs, sub: sub}, nil -} - -// WatchSubmitterAdded is a free log subscription operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. -// -// Solidity: event SubmitterAdded(address indexed submitter) -func (_Submitter *SubmitterFilterer) WatchSubmitterAdded(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterAdded, submitter []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterAdded", submitterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterSubmitterAdded) - if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSubmitterAdded is a log parse operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. -// -// Solidity: event SubmitterAdded(address indexed submitter) -func (_Submitter *SubmitterFilterer) ParseSubmitterAdded(log types.Log) (*SubmitterSubmitterAdded, error) { - event := new(SubmitterSubmitterAdded) - if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterSubmitterRemovedIterator is returned from FilterSubmitterRemoved and is used to iterate over the raw logs and unpacked data for SubmitterRemoved events raised by the Submitter contract. -type SubmitterSubmitterRemovedIterator struct { - Event *SubmitterSubmitterRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterSubmitterRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterSubmitterRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterSubmitterRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterSubmitterRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterSubmitterRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterSubmitterRemoved represents a SubmitterRemoved event raised by the Submitter contract. -type SubmitterSubmitterRemoved struct { - Submitter common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSubmitterRemoved is a free log retrieval operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. -// -// Solidity: event SubmitterRemoved(address indexed submitter) -func (_Submitter *SubmitterFilterer) FilterSubmitterRemoved(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterRemovedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterRemoved", submitterRule) - if err != nil { - return nil, err - } - return &SubmitterSubmitterRemovedIterator{contract: _Submitter.contract, event: "SubmitterRemoved", logs: logs, sub: sub}, nil -} - -// WatchSubmitterRemoved is a free log subscription operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. -// -// Solidity: event SubmitterRemoved(address indexed submitter) -func (_Submitter *SubmitterFilterer) WatchSubmitterRemoved(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterRemoved, submitter []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterRemoved", submitterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterSubmitterRemoved) - if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSubmitterRemoved is a log parse operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. -// -// Solidity: event SubmitterRemoved(address indexed submitter) -func (_Submitter *SubmitterFilterer) ParseSubmitterRemoved(log types.Log) (*SubmitterSubmitterRemoved, error) { - event := new(SubmitterSubmitterRemoved) - if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterWithdrawalCreditedIterator is returned from FilterWithdrawalCredited and is used to iterate over the raw logs and unpacked data for WithdrawalCredited events raised by the Submitter contract. -type SubmitterWithdrawalCreditedIterator struct { - Event *SubmitterWithdrawalCredited // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterWithdrawalCreditedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalCredited) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalCredited) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterWithdrawalCreditedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterWithdrawalCreditedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterWithdrawalCredited represents a WithdrawalCredited event raised by the Submitter contract. -type SubmitterWithdrawalCredited struct { - Submitter common.Address - Amount *big.Int - TotalCredit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawalCredited is a free log retrieval operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. -// -// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) -func (_Submitter *SubmitterFilterer) FilterWithdrawalCredited(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterWithdrawalCreditedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalCredited", submitterRule) - if err != nil { - return nil, err - } - return &SubmitterWithdrawalCreditedIterator{contract: _Submitter.contract, event: "WithdrawalCredited", logs: logs, sub: sub}, nil -} - -// WatchWithdrawalCredited is a free log subscription operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. -// -// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) -func (_Submitter *SubmitterFilterer) WatchWithdrawalCredited(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalCredited, submitter []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalCredited", submitterRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterWithdrawalCredited) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalCredited", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawalCredited is a log parse operation binding the contract event 0x335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4. -// -// Solidity: event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit) -func (_Submitter *SubmitterFilterer) ParseWithdrawalCredited(log types.Log) (*SubmitterWithdrawalCredited, error) { - event := new(SubmitterWithdrawalCredited) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalCredited", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterWithdrawalPaidIterator is returned from FilterWithdrawalPaid and is used to iterate over the raw logs and unpacked data for WithdrawalPaid events raised by the Submitter contract. -type SubmitterWithdrawalPaidIterator struct { - Event *SubmitterWithdrawalPaid // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterWithdrawalPaidIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalPaid) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalPaid) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterWithdrawalPaidIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterWithdrawalPaidIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterWithdrawalPaid represents a WithdrawalPaid event raised by the Submitter contract. -type SubmitterWithdrawalPaid struct { - Submitter common.Address - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawalPaid is a free log retrieval operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. -// -// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) FilterWithdrawalPaid(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterWithdrawalPaidIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalPaid", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return &SubmitterWithdrawalPaidIterator{contract: _Submitter.contract, event: "WithdrawalPaid", logs: logs, sub: sub}, nil -} - -// WatchWithdrawalPaid is a free log subscription operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. -// -// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) WatchWithdrawalPaid(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalPaid, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalPaid", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterWithdrawalPaid) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalPaid", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawalPaid is a log parse operation binding the contract event 0xebb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f46. -// -// Solidity: event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) ParseWithdrawalPaid(log types.Log) (*SubmitterWithdrawalPaid, error) { - event := new(SubmitterWithdrawalPaid) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalPaid", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SubmitterWithdrawalRequestedIterator is returned from FilterWithdrawalRequested and is used to iterate over the raw logs and unpacked data for WithdrawalRequested events raised by the Submitter contract. -type SubmitterWithdrawalRequestedIterator struct { - Event *SubmitterWithdrawalRequested // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SubmitterWithdrawalRequestedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalRequested) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SubmitterWithdrawalRequested) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SubmitterWithdrawalRequestedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SubmitterWithdrawalRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SubmitterWithdrawalRequested represents a WithdrawalRequested event raised by the Submitter contract. -type SubmitterWithdrawalRequested struct { - Submitter common.Address - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawalRequested is a free log retrieval operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. -// -// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) FilterWithdrawalRequested(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterWithdrawalRequestedIterator, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalRequested", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return &SubmitterWithdrawalRequestedIterator{contract: _Submitter.contract, event: "WithdrawalRequested", logs: logs, sub: sub}, nil -} - -// WatchWithdrawalRequested is a free log subscription operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. -// -// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) WatchWithdrawalRequested(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalRequested, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { - - var submitterRule []interface{} - for _, submitterItem := range submitter { - submitterRule = append(submitterRule, submitterItem) - } - var receiverRule []interface{} - for _, receiverItem := range receiver { - receiverRule = append(receiverRule, receiverItem) - } - - logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalRequested", submitterRule, receiverRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SubmitterWithdrawalRequested) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawalRequested is a log parse operation binding the contract event 0x04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32. -// -// Solidity: event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount) -func (_Submitter *SubmitterFilterer) ParseWithdrawalRequested(log types.Log) (*SubmitterWithdrawalRequested, error) { - event := new(SubmitterWithdrawalRequested) - if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/bindings/bindings/submitter_more.go b/bindings/bindings/submitter_more.go deleted file mode 100644 index 1adc44989..000000000 --- a/bindings/bindings/submitter_more.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "encoding/json" - - "morph-l2/bindings/solc" -) - -const SubmitterStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1018_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"minimumStake\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"registered\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"stakeOf\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"exiting\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"claimable\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_uint256)1018_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1017_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1018_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" - -var SubmitterStorageLayout = new(solc.StorageLayout) - -var SubmitterDeployedBin = "0x60806040526004361061018e575f3560e01c80639f8a13d7116100dc578063bfa02ba911610087578063cde4cd1111610062578063cde4cd1114610471578063d13f90b414610490578063ec5ffac2146104af578063f2fde38b146104c4575f80fd5b8063bfa02ba914610407578063c36f41e214610433578063c96be4cb14610452575f80fd5b8063ab8c53dc116100b7578063ab8c53dc14610396578063b2dd5c07146103ab578063bbfefd38146103d9575f80fd5b80639f8a13d714610329578063a3066aab14610358578063a4f209b014610377575f80fd5b8063426233601161013c57806360e274641161011757806360e27464146102ab578063715018a6146102ca5780638da5cb5b146102de575f80fd5b8063426233601461024c57806351cff8d91461027757806352d472eb14610296575f80fd5b8063359289911161016c57806335928991146101fa5780633a4b66f114610219578063402914f514610221575f80fd5b8063072900f9146101925780630d13fd7b146101b3578063233e9903146101db575b5f80fd5b34801561019d575f80fd5b506101b16101ac36600461237c565b6104e3565b005b3480156101be575f80fd5b506101c860995481565b6040519081526020015b60405180910390f35b3480156101e6575f80fd5b506101b16101f536600461239c565b610647565b348015610205575f80fd5b506101b161021436600461239c565b610707565b6101b16107c7565b34801561022c575f80fd5b506101c861023b36600461237c565b609f6020525f908152604090205481565b348015610257575f80fd5b506101c861026636600461237c565b609d6020525f908152604090205481565b348015610282575f80fd5b506101b161029136600461237c565b610990565b3480156102a1575f80fd5b506101c8609a5481565b3480156102b6575f80fd5b506101b16102c536600461237c565b610bbb565b3480156102d5575f80fd5b506101b1610d6f565b3480156102e9575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b348015610334575f80fd5b5061034861034336600461237c565b610d80565b60405190151581526020016101d2565b348015610363575f80fd5b506101b161037236600461237c565b610e11565b348015610382575f80fd5b506101b161039136600461239c565b610f9e565b3480156103a1575f80fd5b506101c8609b5481565b3480156103b6575f80fd5b506103486103c536600461237c565b609c6020525f908152604090205460ff1681565b3480156103e4575f80fd5b506103486103f336600461237c565b609e6020525f908152604090205460ff1681565b348015610412575f80fd5b506097546103049073ffffffffffffffffffffffffffffffffffffffff1681565b34801561043e575f80fd5b506101b161044d36600461237c565b61106b565b34801561045d575f80fd5b506101c861046c36600461237c565b611237565b34801561047c575f80fd5b506101b161048b36600461237c565b611429565b34801561049b575f80fd5b506101b16104aa3660046123b3565b611589565b3480156104ba575f80fd5b506101c860985481565b3480156104cf575f80fd5b506101b16104de36600461237c565b611a8b565b6104eb611b3f565b73ffffffffffffffffffffffffffffffffffffffff811615801590610535575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b8015610566575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6105d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b61064f611b3f565b5f8111801561066057506098548114155b6106c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c8565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b61070f611b3f565b5f8111801561072057506099548114155b610786576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c8565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107cf611bc0565b335f818152609c602052604090205460ff168015610812575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610878576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6e6f74207374616b6561626c650000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546108a8903490612429565b90505f341180156108bb57506098548110155b610921576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b650000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a2505061098e6001606555565b565b610998611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610a16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610a6f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610a9e575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b610b04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420776974686472617761626c650000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff8181165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e835281842080549091166001179055609d825291829020549151918252928516927f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b32910160405180910390a3610bad8183611c3a565b50610bb86001606555565b50565b610bc3611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205480610ccd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f20637265646974000000000000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609f6020526040812055610cfc8382611c56565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fc4b5041307ee38be8c4f25df5d980a372ac8a9a73ea8f459891000a5386f532283604051610d5b91815260200190565b60405180910390a35050610bb86001606555565b610d77611b3f565b61098e5f611d2c565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610dd9575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610e0b575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610e19611bc0565b3373ffffffffffffffffffffffffffffffffffffffff8216610e97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610f25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6e6f742065786974696e6700000000000000000000000000000000000000000060448201526064016105c8565b610f2e81611da2565b610f94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f70656e64696e67206261746368206c696162696c69747900000000000000000060448201526064016105c8565b610bad8183611ea7565b610fa6611b3f565b5f81118015610fb6575060648111155b8015610fc45750609a548114155b61102a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c8565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b611073611b3f565b61107b611bc0565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff1680156110d4575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b61113a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e9092528083208054909216600117909155517ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a19190a273ffffffffffffffffffffffffffffffffffffffff81165f818152609d60205260409081902054905182917f04c56a409d50971e45c5a2d96e5d557d2b0f1d66d40f14b141e4c958b0f39b329161121b91815260200190565b60405180910390a361122d8182611c3a565b610bb86001606555565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016105c8565b6112d8611bc0565b73ffffffffffffffffffffffffffffffffffffffff82166112fa57505f61141a565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c845282852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690915591859055609e90935292208054909216600117909155609a54606490611379908361243c565b6113839190612453565b915061138f828261248b565b609b5f82825461139f9190612429565b90915550506097546113c79073ffffffffffffffffffffffffffffffffffffffff1683611c56565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6114246001606555565b919050565b611431611b3f565b611439611bc0565b73ffffffffffffffffffffffffffffffffffffffff81166114b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c8565b609b5480611520576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e67000000000000000000000000000060448201526064016105c8565b5f609b5561152e8282611c56565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161157691815260200190565b60405180910390a250610bb86001606555565b5f54610100900460ff16158080156115a757505f54600160ff909116105b806115c05750303b1580156115c057505f5460ff166001145b61164c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016105c8565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156116a8575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8616611725576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016105c8565b73ffffffffffffffffffffffffffffffffffffffff85161580159061176057505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6117c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016105c8565b5f841161182f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c8565b5f8311611898576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c8565b5f821180156118a8575060648211155b61190e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c8565b6119166120e8565b61191e612186565b61192786611d2c565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611a83575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611a93611b3f565b73ffffffffffffffffffffffffffffffffffffffff8116611b36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016105c8565b610bb881611d2c565b60335473ffffffffffffffffffffffffffffffffffffffff16331461098e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105c8565b600260655403611c2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105c8565b6002606555565b6001606555565b611c4382611da2565b15611c5257611c528282611ea7565b5050565b805f03611c61575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611cb7576040519150601f19603f3d011682016040523d82523d5f602084013e611cbc565b606091505b5050905080611d27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016105c8565b505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60405173ffffffffffffffffffffffffffffffffffffffff821660248201525f908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f8ef622a800000000000000000000000000000000000000000000000000000000178152609754825192935073ffffffffffffffffffffffffffffffffffffffff16915f9182918291829182918761c350fa92503d915060208214831615611e855760205f803e505f515b828015611e925750816020145b8015611e9c575080155b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d60209081526040808320805490849055609e909252822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590819003611f75578173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f465f604051611f6891815260200190565b60405180910390a3505050565b5f8273ffffffffffffffffffffffffffffffffffffffff168261c350906040515f60405180830381858888f193505050503d805f8114611fd0576040519150601f19603f3d011682016040523d82523d5f602084013e611fd5565b606091505b50509050801561204b578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167febb524abf6b48e81bfe3e2a2ba3d4050bc91b988d1cfaf677a91dc6652865f468460405161203e91815260200190565b60405180910390a36120e2565b73ffffffffffffffffffffffffffffffffffffffff84165f908152609f60205260408120805484929061207f908490612429565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f818152609f6020908152604091829020548251868152918201527f335ec00177f14d116df2d9836dfb84e01159f61d1d9305a2130432fb47806ae4910160405180910390a25b50505050565b5f54610100900460ff1661217e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e612224565b5f54610100900460ff1661221c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e6122c3565b5f54610100900460ff166122ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b61098e33611d2c565b5f54610100900460ff16611c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c8565b803573ffffffffffffffffffffffffffffffffffffffff81168114611424575f80fd5b5f6020828403121561238c575f80fd5b61239582612359565b9392505050565b5f602082840312156123ac575f80fd5b5035919050565b5f805f805f60a086880312156123c7575f80fd5b6123d086612359565b94506123de60208701612359565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e0b57610e0b6123fc565b8082028115828204841417610e0b57610e0b6123fc565b5f82612486577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610e0b57610e0b6123fc56fea164736f6c6343000818000a" - -func init() { - if err := json.Unmarshal([]byte(SubmitterStorageLayoutJSON), SubmitterStorageLayout); err != nil { - panic(err) - } - - layouts["Submitter"] = SubmitterStorageLayout - deployedBytecodes["Submitter"] = SubmitterDeployedBin -} diff --git a/bindings/compile.sh b/bindings/compile.sh index 920a29368..936cec851 100755 --- a/bindings/compile.sh +++ b/bindings/compile.sh @@ -1,6 +1,4 @@ -#!/usr/bin/env bash - -set -euo pipefail +#/bin/bash CONTRACTS_PATH="../contracts/" cd $CONTRACTS_PATH || exit @@ -15,44 +13,33 @@ forge_compile() { CONTRACTS_PATH="../contracts/" cd $CONTRACTS_PATH || exit yarn clean - - config_backup=$(mktemp) - foundry_backup=$(mktemp) - cp hardhat.config.ts "$config_backup" - cp foundry.toml "$foundry_backup" - restore_sources() { - cp "$config_backup" hardhat.config.ts - cp "$foundry_backup" foundry.toml - rm -f "$config_backup" "$foundry_backup" - } - trap restore_sources EXIT - - { - echo 'import "@foundry-rs/hardhat-forge";' - cat "$config_backup" - } > hardhat.config.ts + sed -i '.bak' '10a\ +import "@foundry-rs/hardhat-forge";' hardhat.config.ts yarn directory=$(pwd)"/contracts" # shellcheck disable=SC2034 main_dirname=$(basename "$directory") + backup_extension=".bak" + find "$directory" -mindepth 1 -maxdepth 1 -type d | while read dir; do dirname=$(basename "$dir") # shellcheck disable=SC2116 subdirs=$(echo "'contracts/$dirname'") echo "$subdirs" - awk -v source="$subdirs" 'NR == 2 { $0 = "src = " source } { print }' \ - "$foundry_backup" > foundry.toml + sed -i "$backup_extension" "2s|.*|src = $subdirs|" foundry.toml yarn hardhat compile done - restore_sources - trap - EXIT + sed -i "$backup_extension" "2s|.*|src = 'contracts'|" foundry.toml + sed -i "$backup_extension" '11s/.*//' hardhat.config.ts + rm -rf foundry.toml.bak + rm -rf hardhat.config.ts.bak } #!/bin/bash -if [ "$#" -eq 0 ]; then +if [ ! -n "$1" ]; then echo "hardhat compile" hardhat_compile else diff --git a/bindings/gen_bindings.sh b/bindings/gen_bindings.sh index 886d19d80..619f944f8 100755 --- a/bindings/gen_bindings.sh +++ b/bindings/gen_bindings.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#/bin/bash set -eu CONTRACTS_PATH="../contracts/" @@ -54,5 +54,4 @@ abigen \ # Place import "github.com/ethereum/go-ethereum" to "github.com/morph-l2/go-ethereum" TO_REPLACED_STRING="github.com/ethereum/go-ethereum" NEW_STRING="github.com/morph-l2/go-ethereum" -sed -i.bak -e "s#${TO_REPLACED_STRING}#${NEW_STRING}#g" ./${PACKAGE}/${TYPE_LOWER}.go -rm -f ./${PACKAGE}/${TYPE_LOWER}.go.bak +sed -i "" -e "s#${TO_REPLACED_STRING}#${NEW_STRING}#g" ./${PACKAGE}/${TYPE_LOWER}.go diff --git a/build/lint.go b/build/lint.go index 002a7d1f9..e12ac1cc0 100644 --- a/build/lint.go +++ b/build/lint.go @@ -15,7 +15,7 @@ import ( const ( // GolangCIVersion to be used for linting. - GolangCIVersion = "github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8" + GolangCIVersion = "github.com/golangci/golangci-lint/cmd/golangci-lint@latest" ) // GOBIN environment variable. diff --git a/common/batch/batch_cache.go b/common/batch/batch_cache.go index 3ead3194c..74b987a70 100644 --- a/common/batch/batch_cache.go +++ b/common/batch/batch_cache.go @@ -18,7 +18,6 @@ import ( "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/eth" "github.com/morph-l2/go-ethereum/log" - "github.com/morph-l2/go-ethereum/rpc" "morph-l2/common/blob" ) @@ -70,11 +69,11 @@ type BatchCache struct { l2Clients L2MultiClient rollupContract RollupBatchReader l2Gov L2GovCaller - l1Snapshot *confirmedL1Snapshot // config - batchConfig BatchConfig - maxBlobCount int + batchTimeOut uint64 + blockInterval uint64 + maxBlobCount int // replayL1CommittedBatches is true while InitAndSyncFromRollup is rebuilding committed batches from L2. replayL1CommittedBatches atomic.Bool @@ -95,7 +94,6 @@ func NewBatchCache( isBatchUpgraded func(uint64) bool, isBatchV2Upgraded func(uint64) bool, maxBlobCount int, - batchConfig BatchConfig, l1Client L1HeaderClient, l2Clients L2MultiClient, rollupContract RollupBatchReader, @@ -145,32 +143,22 @@ func NewBatchCache( rollupContract: rollupContract, l2Gov: l2Gov, batchStorage: NewBatchStorage(ldb), - batchConfig: batchConfig, maxBlobCount: maxBlobCount, } } func (bc *BatchCache) Init() error { - bc.initMu.Lock() - defer bc.initMu.Unlock() - return bc.withConfirmedL1Snapshot(bc.initLocked) -} - -func (bc *BatchCache) initLocked() error { - if err := bc.batchConfig.Validate(); err != nil { + err := bc.updateBatchConfigFromGov() + if err != nil { return err } - log.Info("Using static batch config", - "block_interval_blocks", bc.batchConfig.BlockInterval, - "timeout_seconds", bc.batchConfig.Timeout, - "config_hash", bc.batchConfig.Hash()) ci, fi, err := bc.getBatchStatusFromContract() if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } - headerBytes, err := bc.getCanonicalCommittedBatchHeaderByIndex(fi.Uint64()) + headerBytes, err := bc.getLastFinalizeBatchHeaderFromRollupByIndex(fi.Uint64()) if err != nil { - return fmt.Errorf("get canonical finalized batch header err: %w", err) + return fmt.Errorf("get last finalize batch header err: %w", err) } // Initialize BatchCache parent batch information @@ -181,59 +169,12 @@ func (bc *BatchCache) initLocked() error { } lastPackedBlockHeight, err := headerBytes.LastBlockNumber() if err != nil { - store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) + store, err := bc.rollupContract.BatchDataStore(nil, fi) if err != nil { return err } lastPackedBlockHeight = store.BlockNumber.Uint64() } - store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) - if err != nil { - return fmt.Errorf("read finalized batch %d metadata: %w", fi.Uint64(), err) - } - if store.BlockNumber == nil || store.BlockNumber.Uint64() != lastPackedBlockHeight { - return fmt.Errorf("finalized batch %d L2 block mismatch: header=%d store=%v", fi.Uint64(), lastPackedBlockHeight, store.BlockNumber) - } - finalizedRoot, err := bc.rollupContract.FinalizedStateRoots(bc.snapshotCallOpts(), fi) - if err != nil { - return fmt.Errorf("read finalized state root for batch %d: %w", fi.Uint64(), err) - } - if common.Hash(finalizedRoot) != prevStateRoot { - return fmt.Errorf("finalized batch %d state root mismatch: header=%s rollup=%s", fi.Uint64(), prevStateRoot, common.Hash(finalizedRoot)) - } - l2Anchor, err := bc.l2Clients.BlockByNumber(context.Background(), new(big.Int).SetUint64(lastPackedBlockHeight)) - if err != nil { - return fmt.Errorf("read finalized L2 anchor block %d: %w", lastPackedBlockHeight, err) - } - if l2Anchor == nil { - return fmt.Errorf("read finalized L2 anchor block %d: nil block", lastPackedBlockHeight) - } - if l2Anchor.Root() != prevStateRoot { - return fmt.Errorf("finalized L2 anchor state root mismatch: block=%d header=%s l2=%s", lastPackedBlockHeight, prevStateRoot, l2Anchor.Root()) - } - l2AnchorHash := l2Anchor.Hash() - withdrawalRoot, err := headerBytes.WithdrawalRoot() - if err != nil { - return fmt.Errorf("read finalized withdrawal root: %w", err) - } - anchorWithdrawalRoot, err := bc.l2Gov.GetTreeRoot(&bind.CallOpts{Context: bc.ctx, BlockNumber: new(big.Int).SetUint64(lastPackedBlockHeight)}) - if err != nil { - return fmt.Errorf("read L2 withdrawal root at finalized anchor %d: %w", lastPackedBlockHeight, err) - } - if common.Hash(anchorWithdrawalRoot) != withdrawalRoot { - return fmt.Errorf("finalized withdrawal root mismatch: block=%d header=%s l2=%s", lastPackedBlockHeight, withdrawalRoot, common.Hash(anchorWithdrawalRoot)) - } - recheckedL2Anchor, err := bc.l2Clients.BlockByNumber(context.Background(), new(big.Int).SetUint64(lastPackedBlockHeight)) - if err != nil { - return fmt.Errorf("re-read finalized L2 anchor block %d: %w", lastPackedBlockHeight, err) - } - if recheckedL2Anchor == nil || recheckedL2Anchor.Hash() != l2AnchorHash { - actual := common.Hash{} - if recheckedL2Anchor != nil { - actual = recheckedL2Anchor.Hash() - } - return fmt.Errorf("finalized L2 anchor changed during bootstrap: block=%d expected=%s actual=%s", lastPackedBlockHeight, l2AnchorHash, actual) - } totalL1MessagePopped, err := headerBytes.TotalL1MessagePopped() if err != nil { return fmt.Errorf("get total l1 message popped err: %w", err) @@ -243,7 +184,6 @@ func (bc *BatchCache) initLocked() error { bc.prevStateRoot = prevStateRoot bc.lastPackedBlockHeight = lastPackedBlockHeight bc.currentBlockNumber = lastPackedBlockHeight - bc.currentBlockHash = l2AnchorHash bc.totalL1MessagePopped = totalL1MessagePopped bc.mu.Unlock() log.Info("Start assemble batch", "start batch", fi.Uint64(), "end batch", ci.Uint64()) @@ -265,33 +205,30 @@ func (bc *BatchCache) setInitialized() { func (bc *BatchCache) InitFromRollupByRange() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.withConfirmedL1Snapshot(func() error { - if bc.isInitialized() { - return nil - } - if err := bc.initLocked(); err != nil { - return err - } - if err := bc.assembleUnFinalizeBatchHeaderFromL2Blocks(); err != nil { - return err - } - bc.setInitialized() - log.Info("Initialized batch cache success") + if bc.isInitialized() { return nil - }) + } + err := bc.Init() + if err != nil { + return err + } + err = bc.assembleUnFinalizeBatchHeaderFromL2Blocks() + if err != nil { + return err + } + bc.setInitialized() + log.Info("Initialized batch cache success") + return nil } func (bc *BatchCache) InitAndSyncFromDatabase() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.withConfirmedL1Snapshot(bc.initAndSyncFromDatabaseLocked) -} - -func (bc *BatchCache) initAndSyncFromDatabaseLocked() error { if bc.isInitialized() { return nil } - if err := bc.batchConfig.Validate(); err != nil { + err := bc.updateBatchConfigFromGov() + if err != nil { return err } ci, fi, err := bc.getBatchStatusFromContract() @@ -314,11 +251,9 @@ func (bc *BatchCache) initAndSyncFromDatabaseLocked() error { maxIndex = idx } } - // Sealed storage contains batches after the finalized anchor; the anchor - // itself is reconstructed from canonical L1 and is never a local sealed - // checkpoint. Validate only the committed, unfinalized suffix. - for i := fi.Uint64() + 1; i > fi.Uint64() && i <= ci.Uint64(); i++ { - batchHash, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), new(big.Int).SetUint64(i)) + // check batch hash with the batch that already rollup by submitter + for i := fi.Uint64(); i <= ci.Uint64(); i++ { + batchHash, err := bc.rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(i)) if err != nil { return err } @@ -355,7 +290,7 @@ func (bc *BatchCache) initAndSyncFromDatabaseLocked() error { "commitIndex", ci.Uint64(), "finalizeIndex", fi.Uint64()) return bc.deleteBatchStorageAndInitFromRollupLocked() } - store, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), new(big.Int).SetUint64(latestBatchIndex)) + store, err := bc.rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(latestBatchIndex)) if err != nil { log.Error("Failed to load latest batch index from rollup", "error", err, @@ -382,7 +317,7 @@ func (bc *BatchCache) initAndSyncFromDatabaseLocked() error { func (bc *BatchCache) InitAndSyncFromRollup() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.withConfirmedL1Snapshot(bc.initAndSyncFromRollupLocked) + return bc.initAndSyncFromRollupLocked() } func (bc *BatchCache) initAndSyncFromRollupLocked() error { @@ -392,7 +327,7 @@ func (bc *BatchCache) initAndSyncFromRollupLocked() error { bc.replayL1CommittedBatches.Store(true) defer bc.replayL1CommittedBatches.Store(false) - err := bc.initLocked() + err := bc.Init() if err != nil { return err } @@ -440,8 +375,23 @@ func (bc *BatchCache) LatestBatchIndex() (uint64, error) { return bc.parentBatchHeader.BatchIndex() } +func (bc *BatchCache) updateBatchConfigFromGov() error { + interval, err := bc.l2Gov.BatchBlockInterval(nil) + if err != nil { + return err + } + timeout, err := bc.l2Gov.BatchTimeout(nil) + if err != nil { + return err + } + bc.batchTimeOut = timeout.Uint64() + bc.blockInterval = interval.Uint64() + log.Info("Update batch config success", "interval", interval.Uint64(), "timeout", timeout.Uint64()) + return nil +} + func (bc *BatchCache) checkBatchHashCorrect(batchIndex *big.Int, batchHash common.Hash) (bool, error) { - commitBatchHash, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), batchIndex) + commitBatchHash, err := bc.rollupContract.CommittedBatches(nil, batchIndex) if err != nil { return false, err } @@ -456,11 +406,11 @@ func (bc *BatchCache) checkBatchHashCorrect(batchIndex *big.Int, batchHash commo } func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { - latestCommitBatchIndex, err := bc.rollupContract.LastCommittedBatchIndex(bc.snapshotCallOpts()) + latestCommitBatchIndex, err := bc.rollupContract.LastCommittedBatchIndex(nil) if err != nil { return nil, nil, err } - lastFinalizedBatchIndex, err := bc.rollupContract.LastFinalizedBatchIndex(bc.snapshotCallOpts()) + lastFinalizedBatchIndex, err := bc.rollupContract.LastFinalizedBatchIndex(nil) if err != nil { return nil, nil, err } @@ -469,11 +419,11 @@ func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { func (bc *BatchCache) getBatchBlockRange(batchIndex *big.Int) (uint64, uint64, error) { preIndex := new(big.Int).Sub(batchIndex, big.NewInt(1)) - preBatchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), preIndex) + preBatchStorage, err := bc.rollupContract.BatchDataStore(nil, preIndex) if err != nil { return 0, 0, err } - batchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), batchIndex) + batchStorage, err := bc.rollupContract.BatchDataStore(nil, batchIndex) if err != nil { return 0, 0, err } @@ -485,7 +435,7 @@ func (bc *BatchCache) getUnFinalizeBlockRange() (uint64, uint64, *big.Int, error if err != nil { return 0, 0, nil, err } - finalizeBatchStorage, err := bc.rollupContract.BatchDataStore(bc.snapshotCallOpts(), fi) + finalizeBatchStorage, err := bc.rollupContract.BatchDataStore(nil, fi) if err != nil { return 0, 0, nil, err } @@ -716,6 +666,7 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // SealBatch seals the currently accumulated batch, generates batch header and stores to sealedBatches // Parameters: +// - sequencerSetVerifyHash: sequencer set verification hash (obtained from L1 contract) // - blockTimestamp: current block timestamp (used to determine batch version) // // Returns: @@ -729,7 +680,7 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // replayCommittedBatchIndex, when non-nil, is the rollup batch index being re-sealed while syncing // from L1 (InitAndSyncFromRollup). After V2 multi-blob, blob capacity is capped at replayProtocolMaxBlobs // (6), not max_blob_count, without querying L1 CommitBatch logs. -func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { +func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { bc.mu.Lock() defer bc.mu.Unlock() @@ -771,7 +722,7 @@ func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex ) // Create batch header - batchHeader := bc.createBatchHeader(batchDataHash, sidecar, blockTimestamp) + batchHeader := bc.createBatchHeader(batchDataHash, sidecar, crypto.Keccak256Hash(sequencerSets), blockTimestamp) // Calculate batch hash batchHash, err := batchHeader.Hash() @@ -804,21 +755,26 @@ func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex } blockContexts := hexutil.Bytes(blockContextsData) + // Convert sequencerSetVerifyHash to bytes + currentSequencerSetBytes := hexutil.Bytes(sequencerSets) + // Get L1 message count from batch data numL1Messages := bc.batchData.l1TxNum // Store sealed batch information as RPCRollupBatch sealedBatch := ð.RPCRollupBatch{ - Version: uint(version), - Hash: batchHash, - ParentBatchHeader: parentBatchHeaderBytes, - BlockContexts: blockContexts, - PrevStateRoot: bc.prevStateRoot, - PostStateRoot: bc.postStateRoot, - WithdrawRoot: bc.withdrawRoot, - LastBlockNumber: bc.lastPackedBlockHeight, - NumL1Messages: numL1Messages, - Sidecar: *sidecar, + Version: uint(version), + Hash: batchHash, + ParentBatchHeader: parentBatchHeaderBytes, + BlockContexts: blockContexts, + CurrentSequencerSetBytes: currentSequencerSetBytes, + PrevStateRoot: bc.prevStateRoot, + PostStateRoot: bc.postStateRoot, + WithdrawRoot: bc.withdrawRoot, + LastBlockNumber: bc.lastPackedBlockHeight, + NumL1Messages: numL1Messages, + Sidecar: *sidecar, + Signatures: []eth.RPCBatchSignature{}, } bc.sealedBatches[batchIndex] = sealedBatch // Store batch header copy @@ -959,7 +915,7 @@ func (bc *BatchCache) handleBatchSealing(blockTimestamp uint64, sealBlobCap int, } // createBatchHeader creates BatchHeader -func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, blockTimestamp uint64) BatchHeaderBytes { +func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, sequencerSetVerifyHash common.Hash, blockTimestamp uint64) BatchHeaderBytes { blobHashes := []common.Hash{blob.EmptyVersionedHash} if sidecar != nil && len(sidecar.Blobs) > 0 { blobHashes = sidecar.BlobHashes() @@ -986,7 +942,7 @@ func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes. PrevStateRoot: bc.prevStateRoot, PostStateRoot: bc.postStateRoot, WithdrawalRoot: bc.withdrawRoot, - SequencerSetVerifyHash: common.Hash{}, + SequencerSetVerifyHash: sequencerSetVerifyHash, ParentBatchHash: parentBatchHash, } @@ -1158,6 +1114,10 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( } } + sequencerSet, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) + if err != nil { + return nil, fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) + } // Get the last block's timestamp for packing lastBlock, err := bc.l2Clients.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) if err != nil { @@ -1166,7 +1126,7 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, replayCommittedBatchIndex) + batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(sequencerSet, blockTimestamp, replayCommittedBatchIndex) if err != nil { return nil, fmt.Errorf("failed to seal batch: %w", err) } @@ -1220,22 +1180,22 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the configured static timeout. + // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract timeout := false - if bc.batchConfig.Timeout > 0 { + if bc.batchTimeOut > 0 { elapsedTime := nowBlockTime - startBlockTime - if elapsedTime >= bc.batchConfig.Timeout { + if elapsedTime >= bc.batchTimeOut { timeout = true log.Info("Batch timeout reached, must seal batch", "startBlock", startBlockNum, "currentBlock", blockNum, - "elapsedTime", elapsedTime, "batchTimeOut", bc.batchConfig.Timeout) + "elapsedTime", elapsedTime, "batchTimeOut", bc.batchTimeOut) } } // Check if we need to seal batch due to capacity, block interval, or timeout // check ensures batch is sealed before exceeding the maximum timeout - if exceeded || (bc.batchConfig.BlockInterval > 0 && (blockNum-startBlockNum+1) == bc.batchConfig.BlockInterval) || timeout { + if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum-1, "exceeded", exceeded, "timeout", timeout) - batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(ci) + batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(callOpts, ci) if err != nil { return err } @@ -1265,14 +1225,18 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { return nil } -func (bc *BatchCache) SealBatchAndCheck(ci *big.Int) (common.Hash, bool, uint64, error) { +func (bc *BatchCache) SealBatchAndCheck(callOpts *bind.CallOpts, ci *big.Int) (common.Hash, bool, uint64, error) { + sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) + if err != nil { + return common.Hash{}, false, 0, err + } lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, nil) + batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to seal batch: %w", err) } @@ -1410,15 +1374,10 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { callOpts := &bind.CallOpts{ Context: bc.ctx, } - safeHead, err := bc.l2Clients.BlockByNumber(bc.ctx, big.NewInt(int64(rpc.SafeBlockNumber))) + endBlockNum, err := bc.l2Clients.BlockNumber(bc.ctx) if err != nil { - return fmt.Errorf("get fixed L2 safe head: %w", err) - } - if safeHead == nil { - return errors.New("get fixed L2 safe head: nil block") + return err } - endBlockNum := safeHead.NumberU64() - safeHeadHash := safeHead.Hash() if endBlockNum < bc.currentBlockNumber { return fmt.Errorf("has reorg, should check block status current %v, now %v", bc.currentBlockNumber, endBlockNum) } @@ -1428,10 +1387,17 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { } version, _ := bc.parentBatchHeader.Version() if version < 1 { - // V0 headers do not encode lastBlockNumber. Bootstrap already resolved - // and verified it from BatchDataStore at the fixed L1 snapshot, so retain - // that pinned value instead of issuing a new latest-state getter here. - startBlockNum = bc.lastPackedBlockHeight + parentIndex, err := bc.parentBatchHeader.BatchIndex() + if err != nil { + log.Error("failed to get block index", "err", err) + return err + } + store, err := bc.rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(parentIndex)) + if err != nil { + log.Error("failed to get batch store", "err", err) + return err + } + startBlockNum = store.BlockNumber.Uint64() } else { startBlockNum, err = bc.parentBatchHeader.LastBlockNumber() if err != nil { @@ -1445,25 +1411,11 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { return fmt.Errorf("invalid block number") } startBlockNum++ - if currentBlockNum == endBlockNum { - return bc.verifyFixedL2Head(endBlockNum, safeHeadHash) - } - priorBlock, err := bc.l2Clients.BlockByNumber(bc.ctx, new(big.Int).SetUint64(currentBlockNum)) - if err != nil { - return fmt.Errorf("read L2 bootstrap parent block %d: %w", currentBlockNum, err) - } - if priorBlock == nil || priorBlock.NumberU64() != currentBlockNum { - return fmt.Errorf("L2 gap at bootstrap parent: expected=%d got=%v", currentBlockNum, blockNumberOrNil(priorBlock)) - } - previousBlockHash := priorBlock.Hash() // Get start block once to avoid repeated queries startBlock, err := bc.l2Clients.BlockByNumber(bc.ctx, big.NewInt(int64(startBlockNum))) if err != nil { return fmt.Errorf("failed to get start block %d: %w", startBlockNum, err) } - if startBlock == nil || startBlock.NumberU64() != startBlockNum { - return fmt.Errorf("L2 gap at first bootstrap block: expected=%d got=%v", startBlockNum, blockNumberOrNil(startBlock)) - } startBlockTime := startBlock.Time() progressState := batchPackProgressState{} @@ -1486,44 +1438,35 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { if err != nil { return fmt.Errorf("failed to get block %d: %w", blockNum, err) } - if nowBlock == nil || nowBlock.NumberU64() != blockNum { - return fmt.Errorf("L2 gap while packing bootstrap range: expected=%d got=%v", blockNum, blockNumberOrNil(nowBlock)) - } nowBlockTime := nowBlock.Time() - if nowBlock.Hash() != bc.currentProposalHash() { - return fmt.Errorf("L2 block changed while packing bootstrap range: block=%d", blockNum) - } - if nowBlock.ParentHash() != previousBlockHash { - return fmt.Errorf("L2 parent hash discontinuity during bootstrap: block=%d expectedParent=%s actualParent=%s", blockNum, previousBlockHash, nowBlock.ParentHash()) - } - previousBlockHash = nowBlock.Hash() bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the configured static timeout. + // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract timeout := false - if bc.batchConfig.Timeout > 0 { + if bc.batchTimeOut > 0 { elapsedTime := nowBlockTime - startBlockTime - if elapsedTime >= bc.batchConfig.Timeout { + if elapsedTime >= bc.batchTimeOut { timeout = true log.Info("Batch timeout reached, must seal batch", "startBlock", startBlockNum, "currentBlock", blockNum, - "elapsedTime", elapsedTime, "batchTimeOut", bc.batchConfig.Timeout) + "elapsedTime", elapsedTime, "batchTimeOut", bc.batchTimeOut) } } // Check if we need to seal batch due to capacity, block interval, or timeout // check ensures batch is sealed before exceeding the maximum timeout - if exceeded || (bc.batchConfig.BlockInterval > 0 && (blockNum-startBlockNum+1) == bc.batchConfig.BlockInterval) || timeout { + if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum, "exceeded", exceeded, "timeout", timeout) + sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) + if err != nil { + return fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) + } lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } - if lastBlock == nil || lastBlock.NumberU64() != bc.lastPackedBlockHeight { - return fmt.Errorf("L2 gap at last packed block: expected=%d got=%v", bc.lastPackedBlockHeight, blockNumberOrNil(lastBlock)) - } blockTimestamp := lastBlock.Time() - batchIndex, _, _, err := bc.SealBatch(blockTimestamp, nil) + batchIndex, _, _, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) if err != nil { return fmt.Errorf("failed to seal batch: %w", err) } @@ -1536,9 +1479,6 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { if err != nil { return fmt.Errorf("failed to get start block %d: %w", startBlockNum, err) } - if startBlock == nil || startBlock.NumberU64() != startBlockNum { - return fmt.Errorf("L2 gap after sealed bootstrap batch: expected=%d got=%v", startBlockNum, blockNumberOrNil(startBlock)) - } startBlockTime = startBlock.Time() progressState = batchPackProgressState{} } @@ -1548,34 +1488,6 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { return fmt.Errorf("failed to pack block %d: %w", blockNum, err) } } - return bc.verifyFixedL2Head(endBlockNum, safeHeadHash) -} - -func blockNumberOrNil(block *ethtypes.Block) interface{} { - if block == nil { - return nil - } - return block.NumberU64() -} - -func (bc *BatchCache) currentProposalHash() common.Hash { - bc.mu.RLock() - defer bc.mu.RUnlock() - return bc.currentBlockHash -} - -func (bc *BatchCache) verifyFixedL2Head(number uint64, expected common.Hash) error { - head, err := bc.l2Clients.BlockByNumber(bc.ctx, new(big.Int).SetUint64(number)) - if err != nil { - return fmt.Errorf("re-read fixed L2 safe head %d: %w", number, err) - } - if head == nil || head.Hash() != expected { - actual := common.Hash{} - if head != nil { - actual = head.Hash() - } - return fmt.Errorf("L2 safe head changed during bootstrap: number=%d expected=%s actual=%s", number, expected, actual) - } return nil } @@ -1598,13 +1510,13 @@ func (bc *BatchCache) logBatchPackingProgress(startBlockNum, currentBlockNum, st } timePercent := uint64(0) - if bc.batchConfig.Timeout > 0 { - timePercent = progressPercent(elapsedTime, bc.batchConfig.Timeout) + if bc.batchTimeOut > 0 { + timePercent = progressPercent(elapsedTime, bc.batchTimeOut) } blockPercent := uint64(0) - if bc.batchConfig.BlockInterval > 0 { - blockPercent = progressPercent(packedBlocks, bc.batchConfig.BlockInterval) + if bc.blockInterval > 0 { + blockPercent = progressPercent(packedBlocks, bc.blockInterval) } blobPercent := uint64(0) @@ -1673,40 +1585,7 @@ func maxUint64(values ...uint64) uint64 { func (bc *BatchCache) DeleteBatchStorageAndInitFromRollup() error { bc.initMu.Lock() defer bc.initMu.Unlock() - return bc.withConfirmedL1Snapshot(bc.deleteBatchStorageAndInitFromRollupLocked) -} - -// ResetCanonicalBootstrap discards every locally reconstructed/sealed batch and -// clears all in-memory progress. It is used only when cold-start validation -// fails after writes may already have occurred, so the next attempt cannot -// continue from a partial or reorged checkpoint. -func (bc *BatchCache) ResetCanonicalBootstrap() error { - bc.initMu.Lock() - defer bc.initMu.Unlock() - - if err := bc.batchStorage.DeleteAllSealedBatches(); err != nil { - if forceErr := bc.batchStorage.ForceDeleteAllSealedBatches(); forceErr != nil { - return fmt.Errorf("reset canonical bootstrap storage (normal error: %v): %w", err, forceErr) - } - } - - bc.mu.Lock() - defer bc.mu.Unlock() - bc.initDone = false - bc.sealedBatches = make(map[uint64]*eth.RPCRollupBatch) - bc.sealedBatchHeaders = make(map[uint64]*BatchHeaderBytes) - bc.parentBatchHeader = nil - bc.prevStateRoot = common.Hash{} - bc.batchData = nil - bc.totalL1MessagePopped = 0 - bc.postStateRoot = common.Hash{} - bc.withdrawRoot = common.Hash{} - bc.lastPackedBlockHeight = 0 - bc.currentBlockNumber = 0 - bc.currentBlockHash = common.Hash{} - bc.ClearCurrent() - bc.replayL1CommittedBatches.Store(false) - return nil + return bc.deleteBatchStorageAndInitFromRollupLocked() } func (bc *BatchCache) deleteBatchStorageAndInitFromRollupLocked() error { diff --git a/common/batch/batch_cache_genesis_header_test.go b/common/batch/batch_cache_genesis_header_test.go index 6a8db254f..2b984e8f3 100644 --- a/common/batch/batch_cache_genesis_header_test.go +++ b/common/batch/batch_cache_genesis_header_test.go @@ -19,6 +19,10 @@ var ( globalGenesisBatchHeader *BatchHeaderBytes globalGenesisBatchHeaderErr error globalGenesisBatchHeaderOnce sync.Once + + // Global overrides for cache batch config in tests (instead of updateBatchConfigFromGov). + globalBatchTimeoutForTest uint64 = 10000000 + globalBlockIntervalForTest uint64 = 10000 ) func ensureGlobalGenesisBatchHeader() error { @@ -51,6 +55,9 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { if globalGenesisBatchHeader == nil { return ErrKeyNotFound } + // Use global test knobs instead of querying gov config from chain. + cache.batchTimeOut = globalBatchTimeoutForTest + cache.blockInterval = globalBlockIntervalForTest headerCopy := make(BatchHeaderBytes, len(*globalGenesisBatchHeader)) copy(headerCopy, *globalGenesisBatchHeader) cache.parentBatchHeader = &headerCopy @@ -79,10 +86,9 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { } func TestBatchCacheInitWithGlobalGenesisHeader(t *testing.T) { - requireBatchIntegration(t) testDB := openTestKV(t) a := func(uint64) bool { return true } - cache := NewBatchCache(nil, a, 3, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, a, 3, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex done := make(chan error, 1) diff --git a/common/batch/batch_cache_test.go b/common/batch/batch_cache_test.go index 72456b382..3965fa4aa 100644 --- a/common/batch/batch_cache_test.go +++ b/common/batch/batch_cache_test.go @@ -26,9 +26,8 @@ func init() { } func TestBatchCacheInitServer(t *testing.T) { - requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex @@ -60,17 +59,15 @@ func TestBatchCacheInitServer(t *testing.T) { } func TestBatchCacheInit(t *testing.T) { - requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitAndSyncFromRollup() require.NoError(t, err) } func TestBatchCacheInitByBlockRange(t *testing.T) { - requireBatchIntegration(t) testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) } diff --git a/common/batch/batch_header.go b/common/batch/batch_header.go index e5f1fbc4d..71faaf9fd 100644 --- a/common/batch/batch_header.go +++ b/common/batch/batch_header.go @@ -42,25 +42,7 @@ func (b BatchHeaderBytes) validate() error { switch version { case BatchHeaderVersion0: if len(b) != expectedLengthV0 { - // Frozen legacy V0 headers append one 32-byte skipped-message - // bitmap word per 256 popped messages. Current V0 headers are the - // fixed 249-byte form, so accept both exact historical encodings. - if len(b) < expectedLengthV0 { - return ErrInvalidBatchHeaderLength - } - l1MessagePopped := binary.BigEndian.Uint64(b[9:17]) - bitmapWords := l1MessagePopped / 256 - if l1MessagePopped%256 != 0 { - bitmapWords++ - } - maxInt := uint64(^uint(0) >> 1) - if bitmapWords > (maxInt-expectedLengthV0)/32 { - return ErrInvalidBatchHeaderLength - } - legacyLength := expectedLengthV0 + int(bitmapWords)*32 - if len(b) != legacyLength { - return ErrInvalidBatchHeaderLength - } + return ErrInvalidBatchHeaderLength } case BatchHeaderVersion1: if len(b) != expectedLengthV1 { diff --git a/common/batch/batch_header_zero_test.go b/common/batch/batch_header_zero_test.go deleted file mode 100644 index b14f69950..000000000 --- a/common/batch/batch_header_zero_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package batch - -import ( - "testing" - - "github.com/morph-l2/go-ethereum/common" - "github.com/stretchr/testify/require" -) - -func TestNewBatchHeaderSequencerSetVerifyHashIsZeroForAllVersions(t *testing.T) { - tests := []struct { - name string - upgraded bool - v2 bool - wantLen int - }{ - {name: "v0", wantLen: expectedLengthV0}, - {name: "v1", upgraded: true, wantLen: expectedLengthV1}, - {name: "v2", upgraded: true, v2: true, wantLen: expectedLengthV2}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cache := &BatchCache{ - isBatchUpgraded: func(uint64) bool { return test.upgraded }, - isBatchV2Upgraded: func(uint64) bool { return test.v2 }, - } - header := cache.createBatchHeader(common.Hash{1}, nil, 1) - verifyHash, err := header.SequencerSetVerifyHash() - require.NoError(t, err) - require.Equal(t, common.Hash{}, verifyHash) - require.Equal(t, BatchHeaderBytes(make([]byte, 32)), header[185:217]) - require.Len(t, header, test.wantLen) - }) - } -} diff --git a/common/batch/batch_query.go b/common/batch/batch_query.go index ffad39280..21d463294 100644 --- a/common/batch/batch_query.go +++ b/common/batch/batch_query.go @@ -2,834 +2,349 @@ package batch import ( "bytes" - "encoding/binary" + "context" "errors" "fmt" "math/big" - "sort" - "strings" "morph-l2/bindings/bindings" - "morph-l2/common/blob" "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/common" - ethtypes "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/crypto" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" ) -type canonicalCommitEvent struct { - batchIndex uint64 - batchHash common.Hash - raw ethtypes.Log -} - -type canonicalRevertEvent struct { - batchIndex uint64 - batchHash common.Hash - raw ethtypes.Log -} - -func logIdentityLess(a, b ethtypes.Log) bool { - if a.BlockNumber != b.BlockNumber { - return a.BlockNumber < b.BlockNumber - } - if a.TxIndex != b.TxIndex { - return a.TxIndex < b.TxIndex - } - return a.Index < b.Index -} - -// selectCanonicalCommit follows the shared resolver contract from spec 9.3: -// discard commits at/before the last revert and select the last remaining log -// whose hash equals committedBatches[index] at the fixed snapshot. -func selectCanonicalCommit( - index uint64, - expectedHash common.Hash, - commits []canonicalCommitEvent, - reverts []canonicalRevertEvent, -) (*canonicalCommitEvent, error) { - if expectedHash == (common.Hash{}) { - return nil, fmt.Errorf("batch %d has no canonical committed hash at snapshot", index) - } - sort.Slice(commits, func(i, j int) bool { return logIdentityLess(commits[i].raw, commits[j].raw) }) - sort.Slice(reverts, func(i, j int) bool { return logIdentityLess(reverts[i].raw, reverts[j].raw) }) - - var lastRevert *canonicalRevertEvent - for i := range reverts { - if reverts[i].batchIndex == index { - lastRevert = &reverts[i] - } - } - var selected *canonicalCommitEvent - for i := range commits { - candidate := &commits[i] - if candidate.batchIndex != index || candidate.batchHash != expectedHash { - continue - } - if lastRevert != nil && !logIdentityLess(lastRevert.raw, candidate.raw) { - continue - } - selected = candidate - } - if selected == nil { - return nil, fmt.Errorf("no canonical CommitBatch log for batch %d and hash %s", index, expectedHash) - } - return selected, nil -} - -// getCanonicalCommittedBatchHeaderByIndex recovers a complete header from the -// last canonical CommitBatch transaction at the already-fixed L1 snapshot. A -// FinalizeBatch transaction is deliberately never used as a header substitute. -func (bc *BatchCache) getCanonicalCommittedBatchHeaderByIndex(index uint64) (*BatchHeaderBytes, error) { - if bc.l1Snapshot == nil { - return nil, errors.New("canonical batch header lookup requires a confirmed L1 snapshot") - } - expectedRaw, err := bc.rollupContract.CommittedBatches(bc.snapshotCallOpts(), new(big.Int).SetUint64(index)) +// getLastFinalizeBatchHeaderFromRollupByIndex gets the batch header with the specified index from the rollup contract's FinalizeBatch event +// The finalizeBatch function only receives one parameter: batchHeader bytes, so it can be parsed directly from the transaction +// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found +func (bc *BatchCache) getLastFinalizeBatchHeaderFromRollupByIndex(index uint64) (*BatchHeaderBytes, error) { + // Get the current latest block height + latestBlock, err := bc.l1Client.BlockNumber(context.Background()) if err != nil { - return nil, fmt.Errorf("read committed batch %d at snapshot: %w", index, err) + return nil, fmt.Errorf("failed to get latest block number: %w", err) } - expectedHash := common.Hash(expectedRaw) - commits, reverts, err := bc.collectCanonicalBatchEvents(index) - if err != nil { - return nil, err - } - selected, err := selectCanonicalCommit(index, expectedHash, commits, reverts) - if err != nil { - return nil, err - } - tx, pending, err := bc.l1Client.TransactionByHash(bc.ctx, selected.raw.TxHash) - if err != nil { - return nil, fmt.Errorf("load canonical batch %d transaction %s: %w", index, selected.raw.TxHash, err) - } - if tx == nil || pending { - return nil, fmt.Errorf("canonical batch %d transaction %s is missing or pending", index, selected.raw.TxHash) - } - header, err := bc.reconstructCommittedBatchHeader(index, expectedHash, tx) - if err != nil { - return nil, fmt.Errorf("reconstruct canonical batch %d from transaction %s: %w", index, selected.raw.TxHash, err) - } - return &header, nil -} + const blockRange = uint64(10000) // Query 10000 blocks each time + var endBlock uint64 = latestBlock + var startBlock uint64 -func (bc *BatchCache) collectCanonicalBatchEvents(index uint64) ([]canonicalCommitEvent, []canonicalRevertEvent, error) { - const blockRange uint64 = 10_000 - var commits []canonicalCommitEvent - var reverts []canonicalRevertEvent - for start := uint64(0); ; { - end := start + blockRange - 1 - if end < start || end > bc.l1Snapshot.number { - end = bc.l1Snapshot.number + // Start from the latest height, query backwards 10000 blocks each time until data is found + for endBlock > 0 { + // Calculate the start block for this query + if endBlock >= blockRange { + startBlock = endBlock - blockRange + 1 + } else { + startBlock = 0 } - opts, err := bc.snapshotFilterOpts(start, end) - if err != nil { - return nil, nil, err + + // Set query options + filterOpts := &bind.FilterOpts{ + Start: startBlock, + End: &endBlock, } - commitIter, err := bc.rollupContract.FilterCommitBatch(opts, []*big.Int{new(big.Int).SetUint64(index)}, nil) + + // Query the FinalizeBatch event with the corresponding index from the rollup contract + finalizeEventIter, err := bc.rollupContract.FilterFinalizeBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) if err != nil { - return nil, nil, fmt.Errorf("filter CommitBatch %d in L1 range [%d,%d]: %w", index, start, end, err) + // If query fails, continue querying backwards + if startBlock == 0 { + break // Already queried to block 0, exit loop + } + endBlock = startBlock - 1 + continue } - for commitIter.Next() { - event := commitIter.Event - if event == nil || event.BatchIndex == nil || !event.BatchIndex.IsUint64() { - _ = commitIter.Close() - return nil, nil, fmt.Errorf("malformed CommitBatch event for batch %d", index) + defer func() { _ = finalizeEventIter.Close() }() + // Iterate through query results + for finalizeEventIter.Next() { + event := finalizeEventIter.Event + // Get transaction hash from event + txHash := event.Raw.TxHash + + // Get transaction details + tx, _, err := bc.l1Client.TransactionByHash(context.Background(), txHash) + if err != nil { + continue // If getting transaction fails, try next event } - if event.BatchIndex.Uint64() != index || event.Raw.Removed || event.Raw.BlockNumber < start || event.Raw.BlockNumber > end { - _ = commitIter.Close() - return nil, nil, fmt.Errorf("non-canonical CommitBatch event returned for batch %d", index) + + // Parse finalizeBatch transaction data to get batchHeader + batchHeader, err := parseFinalizeBatchTxData(tx.Data()) + if err != nil { + continue // If parsing fails, try next event } - commits = append(commits, canonicalCommitEvent{ - batchIndex: event.BatchIndex.Uint64(), - batchHash: common.Hash(event.BatchHash), - raw: event.Raw, - }) - } - iterErr := commitIter.Error() - closeErr := commitIter.Close() - if iterErr != nil { - return nil, nil, fmt.Errorf("iterate CommitBatch %d in L1 range [%d,%d]: %w", index, start, end, iterErr) - } - if closeErr != nil { - return nil, nil, fmt.Errorf("close CommitBatch iterator for batch %d: %w", index, closeErr) - } - opts, err = bc.snapshotFilterOpts(start, end) - if err != nil { - return nil, nil, err - } - revertIter, err := bc.rollupContract.FilterRevertBatch(opts, []*big.Int{new(big.Int).SetUint64(index)}, nil) - if err != nil { - return nil, nil, fmt.Errorf("filter RevertBatch %d in L1 range [%d,%d]: %w", index, start, end, err) - } - for revertIter.Next() { - event := revertIter.Event - if event == nil || event.BatchIndex == nil || !event.BatchIndex.IsUint64() { - _ = revertIter.Close() - return nil, nil, fmt.Errorf("malformed RevertBatch event for batch %d", index) + // Verify if batch index matches + batchIndex, err := batchHeader.BatchIndex() + if err != nil { + continue } - if event.BatchIndex.Uint64() != index || event.Raw.Removed || event.Raw.BlockNumber < start || event.Raw.BlockNumber > end { - _ = revertIter.Close() - return nil, nil, fmt.Errorf("non-canonical RevertBatch event returned for batch %d", index) + if batchIndex == index { + return &batchHeader, nil } - reverts = append(reverts, canonicalRevertEvent{ - batchIndex: event.BatchIndex.Uint64(), - batchHash: common.Hash(event.BatchHash), - raw: event.Raw, - }) - } - iterErr = revertIter.Error() - closeErr = revertIter.Close() - if iterErr != nil { - return nil, nil, fmt.Errorf("iterate RevertBatch %d in L1 range [%d,%d]: %w", index, start, end, iterErr) - } - if closeErr != nil { - return nil, nil, fmt.Errorf("close RevertBatch iterator for batch %d: %w", index, closeErr) } - if end == bc.l1Snapshot.number { - break + // Continue querying backwards + if endBlock < blockRange { + break // Already queried to block 0, exit loop } - start = end + 1 + endBlock = startBlock - 1 } - return commits, reverts, nil + + return nil, fmt.Errorf("failed to find last finalized batch header for batchIndex %d", index) } -func (bc *BatchCache) reconstructCommittedBatchHeader( - index uint64, - expectedHash common.Hash, - tx *ethtypes.Transaction, -) (BatchHeaderBytes, error) { - if tx == nil { - return nil, errors.New("nil canonical commit transaction") - } - genesis, matched, err := decodeImportGenesisHeader(tx.Data()) +// parseFinalizeBatchTxData parses the finalizeBatch or importGenesisBatch transaction's input data to get BatchHeaderBytes +// Both finalizeBatch(bytes calldata _batchHeader) and importGenesisBatch(bytes calldata _batchHeader) receive one parameter: batchHeader bytes +// Both methods emit FinalizeBatch event, so we need to support parsing both +func parseFinalizeBatchTxData(txData []byte) (BatchHeaderBytes, error) { + // Get rollup ABI + rollupAbi, err := bindings.RollupMetaData.GetAbi() if err != nil { return nil, err } - if matched { - if err := verifyHeaderIdentity(genesis, index, expectedHash); err != nil { - return nil, err - } - if err := bc.verifyFinalizedMessageCursor(genesis); err != nil { - return nil, err - } - return genesis, nil - } - abis, err := DefaultRollupABIs() - if err != nil { - return nil, err - } - decoded, err := decodeBatchCall(tx.Data(), abis) - if err != nil { - return nil, err - } - if decoded.input.Version > BatchHeaderVersion2 { - return nil, fmt.Errorf("canonical commit has unsupported batch version %d", decoded.input.Version) - } - if len(decoded.explicitHeader) > 0 { - if err := verifyHeaderIdentity(decoded.explicitHeader, index, expectedHash); err != nil { - return nil, fmt.Errorf("invalid explicit header in %s.%s: %w", decoded.era, decoded.method, err) - } - if err := bc.verifyFinalizedMessageCursor(decoded.explicitHeader); err != nil { - return nil, err - } - return decoded.explicitHeader, nil + // Check if the first 4 bytes of transaction data match the method ID + if len(txData) < 4 { + return nil, errors.New("transaction data too short") } - parent := BatchHeaderBytes(decoded.input.ParentBatchHeader) - parentIndex, err := parent.BatchIndex() - if err != nil { - return nil, fmt.Errorf("decode parent batch header index: %w", err) - } - if parentIndex == ^uint64(0) || parentIndex+1 != index { - return nil, fmt.Errorf("canonical commit parent index mismatch: parent=%d current=%d", parentIndex, index) - } - parentHash, err := parent.Hash() - if err != nil { - return nil, fmt.Errorf("hash parent batch header: %w", err) - } - parentCursor, err := parent.TotalL1MessagePopped() - if err != nil { - return nil, fmt.Errorf("decode parent L1 message cursor: %w", err) - } + methodID := txData[:4] - queue, err := bc.l1MessageQueue() - if err != nil { - return nil, err - } - var ( - dataHash common.Hash - l1MessageCount uint64 - ) - switch decoded.era { - case "pre-submitter", "current": - l1MessageCount = uint64(decoded.input.NumL1Messages) - if l1MessageCount > ^uint64(0)-parentCursor { - return nil, fmt.Errorf("L1 message cursor overflow: parent=%d batch=%d", parentCursor, l1MessageCount) - } - data := make([]byte, 10, 10+32*int(l1MessageCount)) - binary.BigEndian.PutUint64(data[:8], decoded.input.LastBlockNumber) - binary.BigEndian.PutUint16(data[8:10], decoded.input.NumL1Messages) - for i := uint64(0); i < l1MessageCount; i++ { - messageHash, err := queue.GetCrossDomainMessage( - bc.snapshotCallOpts(), - new(big.Int).SetUint64(parentCursor+i), - ) - if err != nil { - return nil, fmt.Errorf("read L1 message %d for canonical batch %d: %w", parentCursor+i, index, err) - } - data = append(data, messageHash[:]...) - } - dataHash = crypto.Keccak256Hash(data) - case "before-move-block-context", "legacy": - data, count, err := bc.reconstructBlockContextData(decoded, parentCursor, queue) - if err != nil { - return nil, err - } - l1MessageCount = count - dataHash = crypto.Keccak256Hash(data) - default: - return nil, fmt.Errorf("unsupported canonical commit ABI era %q", decoded.era) - } - if l1MessageCount > ^uint64(0)-parentCursor { - return nil, fmt.Errorf("L1 message cursor overflow: parent=%d batch=%d", parentCursor, l1MessageCount) + // Try to get finalizeBatch method + finalizeBatchMethod, ok := rollupAbi.Methods["finalizeBatch"] + if !ok { + return nil, errors.New("finalizeBatch method not found in ABI") } - totalCursor := parentCursor + l1MessageCount - blobHashRaw, err := bc.rollupContract.BatchBlobVersionedHashes( - bc.snapshotCallOpts(), - new(big.Int).SetUint64(index), - ) - if err != nil { - return nil, fmt.Errorf("read blob hash for canonical batch %d: %w", index, err) - } - blobCommitHash, err := canonicalBlobCommitHash(tx, decoded, common.Hash(blobHashRaw)) - if err != nil { - return nil, err - } - base := BatchHeaderV0{ - BatchIndex: index, - L1MessagePopped: l1MessageCount, - TotalL1MessagePopped: totalCursor, - DataHash: dataHash, - BlobVersionedHash: blobCommitHash, - PrevStateRoot: common.Hash(decoded.input.PrevStateRoot), - PostStateRoot: common.Hash(decoded.input.PostStateRoot), - WithdrawalRoot: common.Hash(decoded.input.WithdrawalRoot), - SequencerSetVerifyHash: decoded.sequencerSetHash, - ParentBatchHash: parentHash, - } - var header BatchHeaderBytes - if decoded.input.Version >= BatchHeaderVersion1 { - header = BatchHeaderV1{ - BatchHeaderV0: base, - LastBlockNumber: decoded.input.LastBlockNumber, - }.Bytes() - if decoded.input.Version == BatchHeaderVersion2 { - header[0] = BatchHeaderVersion2 - } + var method abi.Method + var methodName string + + // Check if method ID matches finalizeBatch + if bytes.Equal(methodID, finalizeBatchMethod.ID) { + method = finalizeBatchMethod + methodName = "finalizeBatch" } else { - header = base.Bytes() - if decoded.era == "legacy" { - header = append(header, decoded.skippedBitmap...) + // Try importGenesisBatch method + importGenesisBatchMethod, ok := rollupAbi.Methods["importGenesisBatch"] + if !ok { + return nil, errors.New("importGenesisBatch method not found in ABI") + } + if bytes.Equal(methodID, importGenesisBatchMethod.ID) { + method = importGenesisBatchMethod + methodName = "importGenesisBatch" + } else { + return nil, fmt.Errorf("transaction is not a finalizeBatch or importGenesisBatch call, methodID: %x", methodID) } } - if err := verifyHeaderIdentity(header, index, expectedHash); err != nil { - return nil, fmt.Errorf("reconstructed %s.%s header: %w", decoded.era, decoded.method, err) - } - if err := bc.verifyFinalizedMessageCursor(header); err != nil { - return nil, err - } - return header, nil -} -func canonicalBlobCommitHash( - tx *ethtypes.Transaction, - decoded *decodedBatchCall, - stored common.Hash, -) (common.Hash, error) { - hashes := tx.BlobHashes() - if len(hashes) == 0 { - if decoded.era == "current" && decoded.method == "commitBatch" { - return common.Hash{}, errors.New("current canonical commitBatch has no fresh blob hash") - } - if stored != (common.Hash{}) { - return stored, nil - } - if decoded.method == "commitState" || decoded.input.Version >= BatchHeaderVersion2 { - return common.Hash{}, fmt.Errorf("%s.%s has no recoverable stored blob hash", decoded.era, decoded.method) - } - // Frozen V0/V1 commitBatch transactions mined before blobs were - // available used the protocol's non-zero empty versioned hash. - return blob.EmptyVersionedHash, nil + // Parse parameters (only one parameter: batchHeader bytes) + args, err := method.Inputs.Unpack(txData[4:]) + if err != nil { + return nil, fmt.Errorf("failed to unpack %s transaction parameters: %w", methodName, err) } - var fromTransaction common.Hash - if decoded.input.Version >= BatchHeaderVersion2 { - fromTransaction = aggregateBlobHashes(hashes) - } else { - fromTransaction = hashes[0] - } - if stored != (common.Hash{}) && stored != fromTransaction { - return common.Hash{}, fmt.Errorf("canonical batch blob hash mismatch: stored=%s transaction=%s", stored, fromTransaction) + if len(args) == 0 { + return nil, fmt.Errorf("no arguments found in %s transaction", methodName) } - return fromTransaction, nil -} -func decodeImportGenesisHeader(data []byte) (BatchHeaderBytes, bool, error) { - rollupABI, err := bindings.RollupMetaData.GetAbi() - if err != nil { - return nil, false, err - } - method, ok := rollupABI.Methods["importGenesisBatch"] - if !ok || len(data) < 4 || !bytes.Equal(data[:4], method.ID) { - return nil, false, nil - } - args, err := method.Inputs.Unpack(data[4:]) - if err != nil { - return nil, true, fmt.Errorf("decode importGenesisBatch: %w", err) - } - if len(args) != 1 { - return nil, true, fmt.Errorf("decode importGenesisBatch: expected one argument, got %d", len(args)) - } - header, ok := args[0].([]byte) + // The first parameter is batchHeader bytes + batchHeaderBytes, ok := args[0].([]byte) if !ok { - return nil, true, errors.New("decode importGenesisBatch: invalid header argument") + return nil, fmt.Errorf("failed to cast batchHeader to []byte in %s transaction", methodName) } - return BatchHeaderBytes(bytes.Clone(header)), true, nil -} -func verifyHeaderIdentity(header BatchHeaderBytes, index uint64, expectedHash common.Hash) error { - gotIndex, err := header.BatchIndex() - if err != nil { - return fmt.Errorf("decode batch header index: %w", err) - } - if gotIndex != index { - return fmt.Errorf("batch header index mismatch: event=%d header=%d", index, gotIndex) - } - gotHash, err := header.Hash() - if err != nil { - return fmt.Errorf("hash batch header: %w", err) - } - if gotHash != expectedHash { - return fmt.Errorf("batch header hash mismatch: getter=%s reconstructed=%s", expectedHash, gotHash) - } - return nil + return BatchHeaderBytes(batchHeaderBytes), nil } -func (bc *BatchCache) l1MessageQueue() (*bindings.L1MessageQueueWithGasPriceOracleCaller, error) { - address, err := bc.rollupContract.MessageQueue(bc.snapshotCallOpts()) - if err != nil { - return nil, fmt.Errorf("read Rollup messageQueue at snapshot: %w", err) - } - if address == (common.Address{}) { - return nil, errors.New("Rollup messageQueue is zero at snapshot") - } - queue, err := bindings.NewL1MessageQueueWithGasPriceOracleCaller(address, bc.l1Client) - if err != nil { - return nil, fmt.Errorf("bind L1 message queue %s: %w", address, err) - } - return queue, nil +// batchDataInputStruct represents the parsed batch data input structure from ABI +type batchDataInputStruct struct { + Version uint8 `json:"version"` + ParentBatchHeader []uint8 `json:"parentBatchHeader"` + LastBlockNumber uint64 `json:"lastBlockNumber"` + NumL1Messages uint16 `json:"numL1Messages"` + PrevStateRoot [32]uint8 `json:"prevStateRoot"` + PostStateRoot [32]uint8 `json:"postStateRoot"` + WithdrawalRoot [32]uint8 `json:"withdrawalRoot"` } -func (bc *BatchCache) verifyFinalizedMessageCursor(header BatchHeaderBytes) error { - total, err := header.TotalL1MessagePopped() - if err != nil { - return fmt.Errorf("decode finalized L1 message cursor: %w", err) - } - queue, err := bc.l1MessageQueue() - if err != nil { - return err - } - pending, err := queue.PendingQueueIndex(bc.snapshotCallOpts()) - if err != nil { - return fmt.Errorf("read finalized L1 message queue cursor: %w", err) - } - if pending == nil || !pending.IsUint64() || pending.Uint64() != total { - return fmt.Errorf("finalized L1 message cursor mismatch: header=%d queue=%v", total, pending) - } - next, err := queue.NextCrossDomainMessageIndex(bc.snapshotCallOpts()) - if err != nil { - return fmt.Errorf("read next L1 message queue index: %w", err) - } - if next == nil || !next.IsUint64() || next.Uint64() < total { - return fmt.Errorf("L1 message queue shorter than finalized cursor: header=%d next=%v", total, next) - } - return nil +// batchSignatureInputStruct represents the parsed batch signature input structure from ABI +type batchSignatureInputStruct struct { + SignedSequencersBitmap *big.Int `json:"signedSequencersBitmap"` + SequencerSets []uint8 `json:"sequencerSets"` + Signature []uint8 `json:"signature"` } -func (bc *BatchCache) reconstructBlockContextData( - decoded *decodedBatchCall, - parentCursor uint64, - queue *bindings.L1MessageQueueWithGasPriceOracleCaller, -) ([]byte, uint64, error) { - contexts := decoded.blockContexts - if len(contexts) < 2 { - return nil, 0, fmt.Errorf("%s block contexts are shorter than count prefix", decoded.era) - } - blockCount := int(binary.BigEndian.Uint16(contexts[:2])) - if blockCount == 0 || len(contexts) != 2+blockCount*60 { - return nil, 0, fmt.Errorf("%s block context length mismatch: blocks=%d bytes=%d", decoded.era, blockCount, len(contexts)) - } - data := make([]byte, 0, blockCount*58) - var messageCount uint64 - for i := 0; i < blockCount; i++ { - contextBytes := contexts[2+i*60 : 2+(i+1)*60] - data = append(data, contextBytes[:58]...) - messageCount += uint64(binary.BigEndian.Uint16(contextBytes[58:60])) - } - if decoded.era == "legacy" { - expectedBitmapBytes := int((messageCount + 255) / 256 * 32) - if len(decoded.skippedBitmap) != expectedBitmapBytes { - return nil, 0, fmt.Errorf("legacy skipped bitmap length mismatch: messages=%d expected=%d actual=%d", messageCount, expectedBitmapBytes, len(decoded.skippedBitmap)) - } - } - if messageCount > ^uint64(0)-parentCursor { - return nil, 0, fmt.Errorf("historical L1 message cursor overflow: parent=%d batch=%d", parentCursor, messageCount) - } - for i := uint64(0); i < messageCount; i++ { - if decoded.era == "legacy" && legacyMessageSkipped(decoded.skippedBitmap, i) { - continue - } - messageHash, err := queue.GetCrossDomainMessage( - bc.snapshotCallOpts(), - new(big.Int).SetUint64(parentCursor+i), - ) - if err != nil { - return nil, 0, fmt.Errorf("read historical L1 message %d: %w", parentCursor+i, err) - } - data = append(data, messageHash[:]...) - } - return data, messageCount, nil -} +// convertBatchDataInput converts the parsed struct to bindings.IRollupBatchDataInput +func convertBatchDataInput(s batchDataInputStruct) *bindings.IRollupBatchDataInput { + // Convert []uint8 to []byte + parentBatchHeader := make([]byte, len(s.ParentBatchHeader)) + copy(parentBatchHeader, s.ParentBatchHeader) -func legacyMessageSkipped(bitmap []byte, index uint64) bool { - wordStart := int(index/256) * 32 - bitInWord := index % 256 - byteIndex := wordStart + 31 - int(bitInWord/8) - return byteIndex >= 0 && byteIndex < len(bitmap) && bitmap[byteIndex]&(1< 0 { + parentBatchHeader, err := getLastFinalizeBatchHeaderByIndex(batchIndex - 1) + if err == nil { + parentBytes := parentBatchHeader.Bytes() + if !bytes.Equal(parentBytes, batchDataInput.ParentBatchHeader) { + t.Errorf("❌ ParentBatchHeader mismatch: assembled=%x, commitBatch=%x", parentBytes[:min(32, len(parentBytes))], batchDataInput.ParentBatchHeader[:min(32, len(batchDataInput.ParentBatchHeader))]) + } else { + t.Logf("✓ ParentBatchHeader: match") + } + } + } + + // Compare LastBlockNumber + lastBlock, err := assembledBatchHeader.LastBlockNumber() + if err == nil { + if lastBlock != batchDataInput.LastBlockNumber { + t.Errorf("❌ LastBlockNumber mismatch: assembled=%d, commitBatch=%d", lastBlock, batchDataInput.LastBlockNumber) + } else { + t.Logf("✓ LastBlockNumber: %d (match)", lastBlock) + } + } + + // Compare NumL1Messages + l1MsgPopped, err := assembledBatchHeader.L1MessagePopped() + require.NoError(t, err) + if l1MsgPopped != uint64(batchDataInput.NumL1Messages) { + t.Errorf("❌ NumL1Messages mismatch: assembled=%d, commitBatch=%d", l1MsgPopped, batchDataInput.NumL1Messages) + } else { + t.Logf("✓ NumL1Messages: %d (match)", l1MsgPopped) + } + + // Compare PrevStateRoot + prevStateRoot, err := assembledBatchHeader.PrevStateRoot() + require.NoError(t, err) + prevStateRootFromCommit := common.BytesToHash(batchDataInput.PrevStateRoot[:]) + if prevStateRoot != prevStateRootFromCommit { + t.Errorf("❌ PrevStateRoot mismatch: assembled=%x, commitBatch=%x", prevStateRoot, prevStateRootFromCommit) + } else { + t.Logf("✓ PrevStateRoot: %x (match)", prevStateRoot) + } + + // Compare PostStateRoot + postStateRoot, err := assembledBatchHeader.PostStateRoot() + require.NoError(t, err) + postStateRootFromCommit := common.BytesToHash(batchDataInput.PostStateRoot[:]) + if postStateRoot != postStateRootFromCommit { + t.Errorf("❌ PostStateRoot mismatch: assembled=%x, commitBatch=%x", postStateRoot, postStateRootFromCommit) + } else { + t.Logf("✓ PostStateRoot: %x (match)", postStateRoot) + } + + // Compare WithdrawalRoot + withdrawRoot, err := assembledBatchHeader.WithdrawalRoot() + require.NoError(t, err) + withdrawRootFromCommit := common.BytesToHash(batchDataInput.WithdrawalRoot[:]) + if withdrawRoot != withdrawRootFromCommit { + t.Errorf("❌ WithdrawalRoot mismatch: assembled=%x, commitBatch=%x", withdrawRoot, withdrawRootFromCommit) + } else { + t.Logf("✓ WithdrawalRoot: %x (match)", withdrawRoot) + } + + // Compare SequencerSetVerifyHash + sequencerSetsHash := crypto.Keccak256Hash(batchSignatureInput.SequencerSets) + seqHash, err := assembledBatchHeader.SequencerSetVerifyHash() + require.NoError(t, err) + if seqHash != sequencerSetsHash { + t.Errorf("❌ SequencerSetVerifyHash mismatch: assembled=%x, from SequencerSets=%x", seqHash, sequencerSetsHash) + } else { + t.Logf("✓ SequencerSetVerifyHash: %x (match)", seqHash) + } + + if seqHash != sequencerSetVerifyHash { + t.Errorf("❌ SequencerSetVerifyHash mismatch with provided hash: assembled=%x, provided=%x", seqHash, sequencerSetVerifyHash) + } else { + t.Logf("✓ SequencerSetVerifyHash matches provided hash: %x", sequencerSetVerifyHash) + } +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// getLastFinalizeBatchHeaderByIndex gets the batch header with the specified index from the rollup contract's FinalizeBatch event +// The finalizeBatch function only receives one parameter: batchHeader bytes, so it can be parsed directly from the transaction +// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found +func getLastFinalizeBatchHeaderByIndex(index uint64) (*BatchHeaderBytes, error) { + // Get the current latest block height + latestBlock, err := l1Client.BlockNumber(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to get latest block number: %w", err) + } + + const blockRange = uint64(10000) // Query 10000 blocks each time + var endBlock uint64 = latestBlock + var startBlock uint64 + + // Start from the latest height, query backwards 10000 blocks each time until data is found + for endBlock > 0 { + // Calculate the start block for this query + if endBlock >= blockRange { + startBlock = endBlock - blockRange + 1 + } else { + startBlock = 0 + } + + // Set query options + filterOpts := &bind.FilterOpts{ + Start: startBlock, + End: &endBlock, + } + + // Query the FinalizeBatch event with the corresponding index from the rollup contract + finalizeEventIter, err := rollupContract.FilterFinalizeBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) + if err != nil { + // If query fails, continue querying backwards + if endBlock < blockRange { + break // Already queried to block 0, exit loop + } + endBlock = startBlock - 1 + continue + } + + // Iterate through query results + for finalizeEventIter.Next() { + event := finalizeEventIter.Event + // Get transaction hash from event + txHash := event.Raw.TxHash + + // Get transaction details + tx, _, err := l1Client.TransactionByHash(context.Background(), txHash) + if err != nil { + continue // If getting transaction fails, try next event + } + + // Parse finalizeBatch transaction data to get batchHeader + batchHeader, err := parseFinalizeBatchTxData(tx.Data()) + if err != nil { + continue // If parsing fails, try next event + } + + // Verify if batch index matches + batchIndex, err := batchHeader.BatchIndex() + if err != nil { + continue + } + if batchIndex == index { + finalizeEventIter.Close() + return &batchHeader, nil + } + } + finalizeEventIter.Close() + + // Continue querying backwards + if endBlock < blockRange { + break // Already queried to block 0, exit loop + } + endBlock = startBlock - 1 + } + + return nil, ErrBatchNotFound +} + +func getInfosFromContract() (*big.Int, *big.Int) { + latestCommitBatchIndex, _ := rollupContract.LastCommittedBatchIndex(nil) + lastFinalizedBatchIndex, _ := rollupContract.LastFinalizedBatchIndex(nil) + return latestCommitBatchIndex, lastFinalizedBatchIndex +} + +func getFirstUnFinalizeBatchBlockNumRange(lastFinalizedBatchIndex *big.Int) (*big.Int, *big.Int, error) { + fis, err := rollupContract.BatchDataStore(nil, lastFinalizedBatchIndex) + if err != nil { + return nil, nil, err + } + ufis, err := rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(lastFinalizedBatchIndex.Uint64()+1)) + if err != nil { + return nil, nil, err + } + + return fis.BlockNumber, ufis.BlockNumber, nil +} + +// getCommitBatchDataByIndex gets batchDataInput and batchSignatureInput with the specified index from the rollup contract's CommitBatch event +// Reference the implementation of getLastFinalizeBatchHeaderByIndex +// Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found +func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, *bindings.IRollupBatchSignatureInput, error) { + // Get the current latest block height + latestBlock, err := l1Client.BlockNumber(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("failed to get latest block number: %w", err) + } + + const blockRange = uint64(10000) // Query 10000 blocks each time + var endBlock uint64 = latestBlock + var startBlock uint64 + + // Start from the latest height, query backwards 10000 blocks each time until data is found + for endBlock > 0 { + // Calculate the start block for this query + if endBlock >= blockRange { + startBlock = endBlock - blockRange + 1 + } else { + startBlock = 0 + } + + // Set query options + filterOpts := &bind.FilterOpts{ + Start: startBlock, + End: &endBlock, + } + + // Query the CommitBatch event with the corresponding index from the rollup contract + commitEventIter, err := rollupContract.FilterCommitBatch(filterOpts, []*big.Int{new(big.Int).SetUint64(index)}, nil) + if err != nil { + // If query fails, continue querying backwards + if endBlock < blockRange { + break // Already queried to block 0, exit loop + } + endBlock = startBlock - 1 + continue + } + + // Iterate through query results + for commitEventIter.Next() { + event := commitEventIter.Event + // Get transaction hash from event + txHash := event.Raw.TxHash + + // Get transaction details + tx, _, err := l1Client.TransactionByHash(context.Background(), txHash) + if err != nil { + return nil, nil, fmt.Errorf("failed to get transaction by hash: %w", err) + } + + // Parse commitBatch transaction data to get batchDataInput and batchSignatureInput + batchDataInput, batchSignatureInput, err := parseCommitBatchTxData(tx.Data()) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse commit batch data: %w", err) + } + + // Verify if batch index matches (by checking batchIndex in parentBatchHeader) + if len(batchDataInput.ParentBatchHeader) > 0 { + parentHeader := BatchHeaderBytes(batchDataInput.ParentBatchHeader) + parentBatchIndex, err := parentHeader.BatchIndex() + if err == nil && parentBatchIndex+1 == index { + commitEventIter.Close() + return batchDataInput, batchSignatureInput, nil + } + } + } + commitEventIter.Close() + + // Continue querying backwards + if endBlock < blockRange { + break // Already queried to block 0, exit loop + } + endBlock = startBlock - 1 + } + + return nil, nil, ErrBatchNotFound +} + +// assembleBatchHeaderFromL2Blocks fetches blocks from L2 client in the specified range and assembles batchHeader +// Parameters: +// - bc: BatchCache instance (parentBatchHeader and prevStateRoot already initialized) +// - startBlockNum: starting block number +// - endBlockNum: ending block number +// - sequencerSetVerifyHash: sequencer set verification hash +// - l2Client: L2 client +// +// Returns: +// - batchHeader: assembled batchHeader +// - error: returns error if assembly fails +func assembleBatchHeaderFromL2Blocks( + bc *BatchCache, + startBlockNum, endBlockNum uint64, + sequencerBytes []byte, + l2Client *ethclient.Client, + l2Gov L2GovCaller, +) (*BatchHeaderBytes, error) { + ctx := context.Background() + + // Fetch blocks from L2 client in the specified range and accumulate to batch + for blockNum := startBlockNum; blockNum <= endBlockNum; blockNum++ { + root, err := l2Gov.GetTreeRoot(&bind.CallOpts{ + Context: ctx, + BlockNumber: new(big.Int).SetUint64(blockNum), + }) + if err != nil { + return nil, fmt.Errorf("failed to get withdraw root at block %d: %w", blockNum, err) + } + // Check capacity and store to current + exceeded, err := bc.CalculateCapWithProposalBlock(blockNum, root) + if err != nil { + return nil, fmt.Errorf("failed to calculate cap with block %d: %w", blockNum, err) + } + + // Pack current block (confirm and append to batch) + if err = bc.PackCurrentBlock(blockNum); err != nil { + return nil, fmt.Errorf("failed to pack block %d: %w", blockNum, err) + } + + // If capacity exceeds limit, can stop early (optional) + _ = exceeded // Checked but not used in this test + } + + // Get the last block's timestamp for packing + lastBlock, err := l2Client.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) + if err != nil { + return nil, fmt.Errorf("failed to get last block %d: %w", endBlockNum, err) + } + blockTimestamp := lastBlock.Time() + + // Seal batch and generate batchHeader + batchIndex, batchHeaderBytes, _, err := bc.SealBatch(sequencerBytes, blockTimestamp, nil) + if err != nil { + return nil, fmt.Errorf("failed to seal batch: %w", err) + } + + // Get the sealed batch header + _, found := bc.GetSealedBatch(batchIndex) + if !found { + return nil, fmt.Errorf("sealed batch not found for index %d", batchIndex) + } + + return &batchHeaderBytes, nil } diff --git a/common/batch/batch_storage_test.go b/common/batch/batch_storage_test.go index fceea3dcc..9ceee7da2 100644 --- a/common/batch/batch_storage_test.go +++ b/common/batch/batch_storage_test.go @@ -233,7 +233,7 @@ func TestSealBatchPropagatesStoreErrorAndKeepsState(t *testing.T) { originalBatchData := bc.batchData originalParent := bc.parentBatchHeader - _, _, _, err := bc.SealBatch(1, nil) + _, _, _, err := bc.SealBatch([]byte{1}, 1, nil) require.ErrorIs(t, err, errWriteBatchUnavailable) require.Empty(t, bc.sealedBatches) require.Empty(t, bc.sealedBatchHeaders) diff --git a/common/batch/canonical_bootstrap_test.go b/common/batch/canonical_bootstrap_test.go deleted file mode 100644 index fd9a58a02..000000000 --- a/common/batch/canonical_bootstrap_test.go +++ /dev/null @@ -1,386 +0,0 @@ -package batch - -import ( - "bytes" - "context" - "encoding/binary" - "errors" - "math/big" - "testing" - - "morph-l2/bindings/bindings" - - "github.com/holiman/uint256" - "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - ethtypes "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/crypto" - "github.com/morph-l2/go-ethereum/eth" - "github.com/morph-l2/go-ethereum/rpc" - "github.com/stretchr/testify/require" -) - -func TestSelectCanonicalCommitUsesRecommitAfterLastRevert(t *testing.T) { - hash := common.HexToHash("0x1234") - commits := []canonicalCommitEvent{ - {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 10, TxIndex: 1, Index: 2}}, - {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 12, TxIndex: 0, Index: 0}}, - } - reverts := []canonicalRevertEvent{ - {batchIndex: 9, batchHash: hash, raw: ethtypes.Log{BlockNumber: 11, TxIndex: 3, Index: 4}}, - } - - selected, err := selectCanonicalCommit(9, hash, commits, reverts) - require.NoError(t, err) - require.Equal(t, uint64(12), selected.raw.BlockNumber) - - // Ordering includes transaction and log index, not just block number. - commits = append(commits, canonicalCommitEvent{ - batchIndex: 9, - batchHash: hash, - raw: ethtypes.Log{BlockNumber: 12, TxIndex: 0, Index: 3}, - }) - selected, err = selectCanonicalCommit(9, hash, commits, reverts) - require.NoError(t, err) - require.Equal(t, uint(3), selected.raw.Index) -} - -func TestSelectCanonicalCommitRejectsEmptyCheckpoint(t *testing.T) { - _, err := selectCanonicalCommit(7, common.Hash{}, nil, nil) - require.ErrorContains(t, err, "no canonical committed hash") -} - -type queueBackend struct { - messages map[uint64]common.Hash - pending uint64 - next uint64 - callBlocks []uint64 - latest uint64 - headers []*ethtypes.Header - headerReads int - transactions map[common.Hash]*ethtypes.Transaction -} - -func (b *queueBackend) CodeAt(context.Context, common.Address, *big.Int) ([]byte, error) { - return []byte{1}, nil -} - -func (b *queueBackend) CallContract(_ context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - if blockNumber == nil { - return nil, errors.New("queue getter was not pinned to snapshot") - } - b.callBlocks = append(b.callBlocks, blockNumber.Uint64()) - if len(call.Data) < 4 { - return nil, errors.New("short queue calldata") - } - selector := call.Data[:4] - switch { - case bytes.Equal(selector, crypto.Keccak256([]byte("getCrossDomainMessage(uint256)"))[:4]): - if len(call.Data) != 36 { - return nil, errors.New("invalid message getter calldata") - } - index := new(big.Int).SetBytes(call.Data[4:]).Uint64() - hash, ok := b.messages[index] - if !ok { - return nil, errors.New("message index unavailable") - } - return hash.Bytes(), nil - case bytes.Equal(selector, crypto.Keccak256([]byte("pendingQueueIndex()"))[:4]): - return common.LeftPadBytes(new(big.Int).SetUint64(b.pending).Bytes(), 32), nil - case bytes.Equal(selector, crypto.Keccak256([]byte("nextCrossDomainMessageIndex()"))[:4]): - return common.LeftPadBytes(new(big.Int).SetUint64(b.next).Bytes(), 32), nil - default: - return nil, errors.New("unexpected queue getter") - } -} - -func (b *queueBackend) BlockNumber(context.Context) (uint64, error) { return b.latest, nil } - -func (b *queueBackend) HeaderByNumber(context.Context, *big.Int) (*ethtypes.Header, error) { - if len(b.headers) == 0 { - return nil, errors.New("header unavailable") - } - index := b.headerReads - if index >= len(b.headers) { - index = len(b.headers) - 1 - } - b.headerReads++ - return b.headers[index], nil -} - -func (b *queueBackend) TransactionByHash(_ context.Context, hash common.Hash) (*ethtypes.Transaction, bool, error) { - tx, ok := b.transactions[hash] - if !ok { - return nil, false, errors.New("transaction unavailable") - } - return tx, false, nil -} - -type canonicalRollupStub struct { - blobHash common.Hash - queueAddress common.Address - callBlockReads []uint64 -} - -func (r *canonicalRollupStub) record(opts *bind.CallOpts) error { - if opts == nil || opts.BlockNumber == nil { - return errors.New("rollup getter was not pinned to snapshot") - } - r.callBlockReads = append(r.callBlockReads, opts.BlockNumber.Uint64()) - return nil -} - -func (r *canonicalRollupStub) BatchBlobVersionedHashes(opts *bind.CallOpts, _ *big.Int) ([32]byte, error) { - if err := r.record(opts); err != nil { - return [32]byte{}, err - } - return [32]byte(r.blobHash), nil -} - -func (r *canonicalRollupStub) MessageQueue(opts *bind.CallOpts) (common.Address, error) { - if err := r.record(opts); err != nil { - return common.Address{}, err - } - return r.queueAddress, nil -} - -func (*canonicalRollupStub) CommittedBatches(*bind.CallOpts, *big.Int) ([32]byte, error) { - return [32]byte{}, errors.New("not implemented") -} -func (*canonicalRollupStub) LastCommittedBatchIndex(*bind.CallOpts) (*big.Int, error) { - return nil, errors.New("not implemented") -} -func (*canonicalRollupStub) LastFinalizedBatchIndex(*bind.CallOpts) (*big.Int, error) { - return nil, errors.New("not implemented") -} -func (*canonicalRollupStub) BatchDataStore(*bind.CallOpts, *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address -}, error) { - return struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address - }{}, errors.New("not implemented") -} -func (*canonicalRollupStub) FinalizedStateRoots(*bind.CallOpts, *big.Int) ([32]byte, error) { - return [32]byte{}, errors.New("not implemented") -} -func (*canonicalRollupStub) FilterCommitBatch(*bind.FilterOpts, []*big.Int, [][32]byte) (*bindings.RollupCommitBatchIterator, error) { - return nil, errors.New("not implemented") -} -func (*canonicalRollupStub) FilterRevertBatch(*bind.FilterOpts, []*big.Int, [][32]byte) (*bindings.RollupRevertBatchIterator, error) { - return nil, errors.New("not implemented") -} - -func TestReconstructCurrentCanonicalCommitAtPinnedSnapshot(t *testing.T) { - parent := BatchHeaderV1{ - BatchHeaderV0: BatchHeaderV0{ - BatchIndex: 7, - TotalL1MessagePopped: 3, - PostStateRoot: common.HexToHash("0x70"), - }, - LastBlockNumber: 90, - }.Bytes() - input := bindings.IRollupBatchDataInput{ - Version: BatchHeaderVersion1, - ParentBatchHeader: parent, - LastBlockNumber: 100, - NumL1Messages: 2, - PrevStateRoot: common.HexToHash("0x70"), - PostStateRoot: common.HexToHash("0x80"), - WithdrawalRoot: common.HexToHash("0x90"), - } - abis, err := DefaultRollupABIs() - require.NoError(t, err) - calldata, err := abis.Current.Pack("commitBatch", input) - require.NoError(t, err) - - messages := map[uint64]common.Hash{ - 3: common.HexToHash("0x300"), - 4: common.HexToHash("0x400"), - } - data := make([]byte, 10) - binary.BigEndian.PutUint64(data[:8], input.LastBlockNumber) - binary.BigEndian.PutUint16(data[8:], input.NumL1Messages) - data = append(data, messages[3].Bytes()...) - data = append(data, messages[4].Bytes()...) - parentHash, err := parent.Hash() - require.NoError(t, err) - blobHash := common.HexToHash("0xb10b") - expected := BatchHeaderV1{ - BatchHeaderV0: BatchHeaderV0{ - BatchIndex: 8, - L1MessagePopped: 2, - TotalL1MessagePopped: 5, - DataHash: crypto.Keccak256Hash(data), - BlobVersionedHash: blobHash, - PrevStateRoot: common.Hash(input.PrevStateRoot), - PostStateRoot: common.Hash(input.PostStateRoot), - WithdrawalRoot: common.Hash(input.WithdrawalRoot), - ParentBatchHash: parentHash, - }, - LastBlockNumber: input.LastBlockNumber, - }.Bytes() - expectedHash, err := expected.Hash() - require.NoError(t, err) - - backend := &queueBackend{messages: messages, pending: 5, next: 6} - rollup := &canonicalRollupStub{ - blobHash: blobHash, - queueAddress: common.HexToAddress("0x1234"), - } - cache := &BatchCache{ - ctx: context.Background(), - l1Client: backend, - rollupContract: rollup, - l1Snapshot: &confirmedL1Snapshot{number: 99, hash: common.HexToHash("0x99")}, - sealedBatches: make(map[uint64]*eth.RPCRollupBatch), - sealedBatchHeaders: make(map[uint64]*BatchHeaderBytes), - } - tx := ethtypes.NewTx(ðtypes.BlobTx{ - ChainID: uint256.NewInt(1), - GasTipCap: uint256.NewInt(1), - GasFeeCap: uint256.NewInt(1), - Value: uint256.NewInt(0), - Data: calldata, - BlobFeeCap: uint256.NewInt(1), - BlobHashes: []common.Hash{blobHash}, - }) - - got, err := cache.reconstructCommittedBatchHeader(8, expectedHash, tx) - require.NoError(t, err) - require.Equal(t, expected, got) - require.NotEmpty(t, rollup.callBlockReads) - for _, number := range rollup.callBlockReads { - require.Equal(t, uint64(99), number) - } - for _, number := range backend.callBlocks { - require.Equal(t, uint64(99), number) - } - - backend.pending = 4 - _, err = cache.reconstructCommittedBatchHeader(8, expectedHash, tx) - require.ErrorContains(t, err, "cursor mismatch") -} - -func TestConfirmedL1SnapshotHashChangeFailsClosed(t *testing.T) { - number := uint64(14) - backend := &queueBackend{ - latest: 20, - headers: []*ethtypes.Header{ - {Number: new(big.Int).SetUint64(number), Extra: []byte("before")}, - {Number: new(big.Int).SetUint64(number), Extra: []byte("after")}, - }, - } - cache := &BatchCache{ctx: context.Background(), l1Client: backend} - err := cache.withConfirmedL1Snapshot(func() error { - require.Equal(t, number, cache.snapshotCallOpts().BlockNumber.Uint64()) - return nil - }) - require.ErrorContains(t, err, "snapshot changed") - require.Nil(t, cache.l1Snapshot) -} - -type scriptedL2 struct { - safe *ethtypes.Block - numbered map[uint64][]*ethtypes.Block - reads map[uint64]int -} - -func (c *scriptedL2) BlockNumber(context.Context) (uint64, error) { return c.safe.NumberU64(), nil } -func (c *scriptedL2) Len() int { return 1 } -func (c *scriptedL2) BlockByNumber(_ context.Context, number *big.Int) (*ethtypes.Block, error) { - if number.Int64() == int64(rpc.SafeBlockNumber) { - return c.safe, nil - } - n := number.Uint64() - values := c.numbered[n] - if len(values) == 0 { - return nil, nil - } - read := c.reads[n] - if read >= len(values) { - read = len(values) - 1 - } - c.reads[n]++ - return values[read], nil -} - -func l2Block(number uint64, marker string) *ethtypes.Block { - return ethtypes.NewBlockWithHeader(ðtypes.Header{ - Number: new(big.Int).SetUint64(number), - Extra: []byte(marker), - }) -} - -func initializedSafeHeadCache(last uint64, l2 L2MultiClient) *BatchCache { - parent := BatchHeaderV1{ - BatchHeaderV0: BatchHeaderV0{BatchIndex: 3}, - LastBlockNumber: last, - }.Bytes() - return &BatchCache{ - ctx: context.Background(), - initDone: true, - parentBatchHeader: &parent, - lastPackedBlockHeight: last, - currentBlockNumber: last, - batchData: NewBatchData(), - batchConfig: BatchConfig{BlockInterval: 100}, - l2Clients: l2, - } -} - -func TestAssembleCurrentBatchRejectsChangedSafeHeadHash(t *testing.T) { - l2 := &scriptedL2{ - safe: l2Block(10, "safe-before"), - numbered: map[uint64][]*ethtypes.Block{10: {l2Block(10, "safe-after")}}, - reads: make(map[uint64]int), - } - cache := initializedSafeHeadCache(10, l2) - err := cache.AssembleCurrentBatchHeader() - require.ErrorContains(t, err, "safe head changed") -} - -func TestAssembleCurrentBatchRejectsL2Gap(t *testing.T) { - l2 := &scriptedL2{ - safe: l2Block(12, "safe"), - numbered: map[uint64][]*ethtypes.Block{ - 10: {l2Block(10, "parent")}, - 11: {l2Block(12, "wrong-height")}, - }, - reads: make(map[uint64]int), - } - cache := initializedSafeHeadCache(10, l2) - err := cache.AssembleCurrentBatchHeader() - require.ErrorContains(t, err, "L2 gap") -} - -func TestResetCanonicalBootstrapLeavesNoCheckpoint(t *testing.T) { - storage := NewBatchStorage(openTestKV(t)) - storeTestChain(t, storage, []uint64{1, 2}) - header := makeTestHeader(2) - cache := &BatchCache{ - initDone: true, - batchStorage: storage, - sealedBatches: map[uint64]*eth.RPCRollupBatch{2: {}}, - sealedBatchHeaders: map[uint64]*BatchHeaderBytes{2: &header}, - parentBatchHeader: &header, - batchData: NewBatchData(), - currentBlockHash: common.HexToHash("0x1234"), - } - - require.NoError(t, cache.ResetCanonicalBootstrap()) - _, err := storage.loadBatchIndices() - require.True(t, isKVNotFound(err), "checkpoint must be absent after rollback: %v", err) - require.False(t, cache.initDone) - require.Empty(t, cache.sealedBatches) - require.Empty(t, cache.sealedBatchHeaders) - require.Nil(t, cache.parentBatchHeader) - require.Nil(t, cache.batchData) - require.Zero(t, cache.currentBlockHash) -} diff --git a/common/batch/commit_test.go b/common/batch/commit_test.go index da2b84c07..c704b885f 100644 --- a/common/batch/commit_test.go +++ b/common/batch/commit_test.go @@ -13,6 +13,7 @@ import ( "morph-l2/common/blob" "github.com/holiman/uint256" + "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/consensus/misc/eip4844" ethtypes "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto" @@ -33,7 +34,7 @@ func TestRollupWithProof(t *testing.T) { } testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, testBatchConfig, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) @@ -52,6 +53,11 @@ func TestRollupWithProof(t *testing.T) { batch, err := cache.Get(latestCommitBatchIndex.Uint64() + 1) require.NoError(t, err) + h := crypto.Keccak256Hash(batch.CurrentSequencerSetBytes) + t.Log("sequencer verify hash:", h.String()) + + signature, err := buildSigInput(batch) + require.NoError(t, err) rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(batch.Version), ParentBatchHeader: batch.ParentBatchHeader, @@ -64,7 +70,7 @@ func TestRollupWithProof(t *testing.T) { tip, gasFeeCap, blobFee, head, err := getGasTipAndCap(l1Client) require.NoError(t, err) - calldata, err := abi.Pack("commitBatch", rollupBatch) + calldata, err := abi.Pack("commitBatch", rollupBatch, *signature) require.NoError(t, err) nonce, err := l1Client.NonceAt(context.Background(), address, nil) require.NoError(t, err) @@ -180,6 +186,15 @@ func getGasTipAndCap(l1client *ethclient.Client) (*big.Int, *big.Int, *big.Int, return tip, gasFeeCap, blobFee, head, nil } +func buildSigInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { + sigData := &bindings.IRollupBatchSignatureInput{ + SignedSequencersBitmap: common.Big0, + SequencerSets: batch.CurrentSequencerSetBytes, + Signature: []byte("0x"), + } + return sigData, nil +} + func sendTx(client *ethclient.Client, txFeeLimit uint64, tx *ethtypes.Transaction) error { if txFeeLimit > 0 { var fee uint64 diff --git a/common/batch/config.go b/common/batch/config.go deleted file mode 100644 index 331a01d82..000000000 --- a/common/batch/config.go +++ /dev/null @@ -1,39 +0,0 @@ -package batch - -import ( - "encoding/binary" - "errors" - - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/crypto" -) - -const batchConfigHashDomain = "morph.batch-config.v1" - -// BatchConfig contains the two static batching thresholds used by a submitter. -// BlockInterval is measured in L2 blocks and Timeout is measured in seconds. -// Either threshold may be disabled independently, but disabling both would make -// it impossible to guarantee that an in-progress batch is ever sealed. -type BatchConfig struct { - BlockInterval uint64 - Timeout uint64 -} - -// Validate checks the protocol-level zero-value rule for static batching -// configuration. -func (c BatchConfig) Validate() error { - if c.BlockInterval == 0 && c.Timeout == 0 { - return errors.New("batch block interval and timeout cannot both be zero") - } - return nil -} - -// Hash returns a stable, domain-separated hash suitable for comparing the -// effective configuration across preflight, startup and backup instances. -func (c BatchConfig) Hash() common.Hash { - encoded := make([]byte, len(batchConfigHashDomain)+16) - copy(encoded, batchConfigHashDomain) - binary.BigEndian.PutUint64(encoded[len(batchConfigHashDomain):], c.BlockInterval) - binary.BigEndian.PutUint64(encoded[len(batchConfigHashDomain)+8:], c.Timeout) - return crypto.Keccak256Hash(encoded) -} diff --git a/common/batch/config_test.go b/common/batch/config_test.go deleted file mode 100644 index 4c98c3db8..000000000 --- a/common/batch/config_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package batch - -import ( - "testing" - - "github.com/morph-l2/go-ethereum/common" - "github.com/stretchr/testify/require" -) - -func TestBatchConfigValidate(t *testing.T) { - tests := []struct { - name string - config BatchConfig - wantErr bool - }{ - {name: "interval only", config: BatchConfig{BlockInterval: 10}}, - {name: "timeout only", config: BatchConfig{Timeout: 60}}, - {name: "both", config: BatchConfig{BlockInterval: 10, Timeout: 60}}, - {name: "both zero", config: BatchConfig{}, wantErr: true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - err := test.config.Validate() - require.Equal(t, test.wantErr, err != nil) - }) - } -} - -func TestBatchConfigHashIsStableAndFieldSensitive(t *testing.T) { - config := BatchConfig{BlockInterval: 10, Timeout: 60} - require.Equal(t, config.Hash(), config.Hash()) - require.NotEqual(t, common.Hash{}, config.Hash()) - require.NotEqual(t, config.Hash(), (BatchConfig{BlockInterval: 11, Timeout: 60}).Hash()) - require.NotEqual(t, config.Hash(), (BatchConfig{BlockInterval: 10, Timeout: 61}).Hash()) -} diff --git a/common/batch/helpers_test.go b/common/batch/helpers_test.go index 081acbe11..f248a2228 100644 --- a/common/batch/helpers_test.go +++ b/common/batch/helpers_test.go @@ -14,8 +14,6 @@ import ( ldbutil "github.com/syndtr/goleveldb/leveldb/util" ) -var testBatchConfig = BatchConfig{BlockInterval: 10_000, Timeout: 10_000_000} - type testLevelDB struct { db *leveldb.DB } @@ -30,13 +28,6 @@ func openTestKV(t *testing.T) SealedBatchKV { return &testLevelDB{db: db} } -func requireBatchIntegration(t *testing.T) { - t.Helper() - if os.Getenv("MORPH_BATCH_INTEGRATION") != "1" { - t.Skip("set MORPH_BATCH_INTEGRATION=1 with local L1/L2 RPCs to run integration test") - } -} - func (d *testLevelDB) GetBytes(key []byte) ([]byte, error) { v, err := d.db.Get(key, nil) if err == ldberrors.ErrNotFound { diff --git a/common/batch/interfaces.go b/common/batch/interfaces.go index 46155df06..739ef422c 100644 --- a/common/batch/interfaces.go +++ b/common/batch/interfaces.go @@ -38,9 +38,7 @@ type SealedBatchKV interface { // L1HeaderClient is the L1 RPC surface required to recover batch headers from events. type L1HeaderClient interface { - bind.ContractCaller BlockNumber(ctx context.Context) (uint64, error) - HeaderByNumber(ctx context.Context, number *big.Int) (*ethtypes.Header, error) TransactionByHash(ctx context.Context, hash common.Hash) (*ethtypes.Transaction, bool, error) } @@ -71,23 +69,22 @@ func (s *SingleL2Client) Len() int { return 1 } // RollupBatchReader is the rollup contract view BatchCache needs (subset of generated Rollup bindings). type RollupBatchReader interface { - BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) - FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) - MessageQueue(opts *bind.CallOpts) (common.Address, error) - FilterCommitBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupCommitBatchIterator, error) - FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) + FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) } -// L2GovCaller is the sole L2 contract view needed by batch assembly. +// L2GovCaller reads batch-related Gov / bridge / sequencer data on L2. type L2GovCaller interface { + BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) + BatchTimeout(opts *bind.CallOpts) (*big.Int, error) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) + GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) } diff --git a/common/batch/l2_gov.go b/common/batch/l2_gov.go index afcab9e07..acfe0c0d0 100644 --- a/common/batch/l2_gov.go +++ b/common/batch/l2_gov.go @@ -1,20 +1,24 @@ package batch import ( + "bytes" "fmt" + "math/big" "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + "github.com/morph-l2/go-ethereum/crypto" ) // L2Gov bundles read-only L2 contracts used when assembling rollup batches. -// The name is retained for API compatibility, but batching no longer reads the -// L2 Sequencer or Gov contracts. Only the withdrawal tree root remains an L2 -// contract dependency. type L2Gov struct { + sequencerContract *bindings.SequencerCaller l2MessagePasserContract *bindings.L2ToL1MessagePasserCaller + govContract *bindings.GovCaller } // NewL2Gov builds an L2Gov using any ContractCaller (e.g. *ethclient.Client or a multi-client backend). @@ -22,16 +26,57 @@ func NewL2Gov(backend bind.ContractCaller) (*L2Gov, error) { if backend == nil { return nil, fmt.Errorf("nil contract backend") } + sequencerContract, err := bindings.NewSequencerCaller(predeploys.SequencerAddr, backend) + if err != nil { + return nil, err + } l2MessagePasserContract, err := bindings.NewL2ToL1MessagePasserCaller(predeploys.L2ToL1MessagePasserAddr, backend) if err != nil { return nil, err } + govContract, err := bindings.NewGovCaller(predeploys.GovAddr, backend) + if err != nil { + return nil, err + } return &L2Gov{ + sequencerContract: sequencerContract, l2MessagePasserContract: l2MessagePasserContract, + govContract: govContract, }, nil } +// SequencerSetVerifyHash gets the sequencer set verify hash from the Sequencer contract. +func (c *L2Gov) SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) { + return c.sequencerContract.SequencerSetVerifyHash(opts) +} + // GetTreeRoot gets the tree root from the L2ToL1MessagePasser contract. func (c *L2Gov) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) { return c.l2MessagePasserContract.GetTreeRoot(opts) } + +// BatchBlockInterval gets the batch block interval from the Gov contract. +func (c *L2Gov) BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) { + return c.govContract.BatchBlockInterval(opts) +} + +// BatchTimeout gets the batch timeout from the Gov contract. +func (c *L2Gov) BatchTimeout(opts *bind.CallOpts) (*big.Int, error) { + return c.govContract.BatchTimeout(opts) +} + +// GetSequencerSetBytes returns sequencer set bytes after hash consistency check. +func (c *L2Gov) GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) { + hash, err := c.sequencerContract.SequencerSetVerifyHash(opts) + if err != nil { + return nil, common.Hash{}, err + } + setBytes, err := c.sequencerContract.GetSequencerSetBytes(opts) + if err != nil { + return nil, common.Hash{}, err + } + if bytes.Equal(hash[:], crypto.Keccak256Hash(setBytes).Bytes()) { + return setBytes, hash, nil + } + return nil, common.Hash{}, fmt.Errorf("sequencer set hash verify failed %v: %v", hexutil.Encode(setBytes), common.BytesToHash(hash[:]).String()) +} diff --git a/common/batch/snapshot.go b/common/batch/snapshot.go deleted file mode 100644 index 604342e30..000000000 --- a/common/batch/snapshot.go +++ /dev/null @@ -1,101 +0,0 @@ -package batch - -import ( - "fmt" - "math/big" - - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" -) - -const canonicalBootstrapConfirmations uint64 = 6 - -type confirmedL1Snapshot struct { - number uint64 - hash common.Hash -} - -// withConfirmedL1Snapshot pins every contract getter and event query performed -// by fn to one confirmed L1 block number, then verifies the block hash again. -// The surrounding initMu serialization guarantees there is at most one active -// bootstrap snapshot per cache. -func (bc *BatchCache) withConfirmedL1Snapshot(fn func() error) error { - if bc.l1Snapshot != nil { - return fn() - } - - latest, err := bc.l1Client.BlockNumber(bc.ctx) - if err != nil { - return fmt.Errorf("read latest L1 block for canonical bootstrap: %w", err) - } - snapshotNumber := uint64(0) - if latest > canonicalBootstrapConfirmations { - snapshotNumber = latest - canonicalBootstrapConfirmations - } - header, err := bc.l1Client.HeaderByNumber(bc.ctx, new(big.Int).SetUint64(snapshotNumber)) - if err != nil { - return fmt.Errorf("read confirmed L1 snapshot %d: %w", snapshotNumber, err) - } - if header == nil { - return fmt.Errorf("read confirmed L1 snapshot %d: nil header", snapshotNumber) - } - if header.Number == nil || header.Number.Uint64() != snapshotNumber { - return fmt.Errorf("confirmed L1 snapshot number mismatch: requested=%d returned=%v", snapshotNumber, header.Number) - } - - bc.l1Snapshot = &confirmedL1Snapshot{number: snapshotNumber, hash: header.Hash()} - opErr := fn() - verifyErr := bc.verifyConfirmedL1Snapshot() - bc.l1Snapshot = nil - if opErr != nil { - if verifyErr != nil { - return fmt.Errorf("canonical bootstrap failed (%v) and snapshot verification failed: %w", opErr, verifyErr) - } - return opErr - } - return verifyErr -} - -func (bc *BatchCache) verifyConfirmedL1Snapshot() error { - if bc.l1Snapshot == nil { - return fmt.Errorf("canonical bootstrap has no confirmed L1 snapshot") - } - header, err := bc.l1Client.HeaderByNumber(bc.ctx, new(big.Int).SetUint64(bc.l1Snapshot.number)) - if err != nil { - return fmt.Errorf("re-read confirmed L1 snapshot %d: %w", bc.l1Snapshot.number, err) - } - if header == nil { - return fmt.Errorf("re-read confirmed L1 snapshot %d: nil header", bc.l1Snapshot.number) - } - if header.Number == nil || header.Number.Uint64() != bc.l1Snapshot.number { - return fmt.Errorf("re-read confirmed L1 snapshot number mismatch: requested=%d returned=%v", bc.l1Snapshot.number, header.Number) - } - if header.Hash() != bc.l1Snapshot.hash { - return fmt.Errorf( - "confirmed L1 snapshot changed during bootstrap: number=%d expected=%s actual=%s", - bc.l1Snapshot.number, - bc.l1Snapshot.hash, - header.Hash(), - ) - } - return nil -} - -func (bc *BatchCache) snapshotCallOpts() *bind.CallOpts { - opts := &bind.CallOpts{Context: bc.ctx} - if bc.l1Snapshot != nil { - opts.BlockNumber = new(big.Int).SetUint64(bc.l1Snapshot.number) - } - return opts -} - -func (bc *BatchCache) snapshotFilterOpts(start, end uint64) (*bind.FilterOpts, error) { - if bc.l1Snapshot == nil { - return nil, fmt.Errorf("canonical event query requires a confirmed L1 snapshot") - } - if end > bc.l1Snapshot.number { - return nil, fmt.Errorf("canonical event query end %d exceeds snapshot %d", end, bc.l1Snapshot.number) - } - endCopy := end - return &bind.FilterOpts{Start: start, End: &endCopy, Context: bc.ctx}, nil -} diff --git a/contracts/abi/archive/README.md b/contracts/abi/archive/README.md deleted file mode 100644 index 15697249e..000000000 --- a/contracts/abi/archive/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Archived production ABIs - -These ABI-only artifacts are immutable compatibility inputs for the centralized -submitter cutover. They were frozen from the pre-Submitter source tree before -the current Rollup ABI was regenerated. - -- `pre-submitter/Rollup.json` decodes the three production submission methods - that still include `BatchSignatureInput`. -- `legacy-l1-staking/IL1Staking.json` preserves the retired public protocol - interface, while `legacy-l1-staking/L1Staking.json` is the complete runtime - interface used by the retirement tooling after the Solidity source is removed. - -Do not regenerate or overwrite these files from the current contracts. diff --git a/contracts/abi/archive/legacy-l1-staking/IL1Staking.json b/contracts/abi/archive/legacy-l1-staking/IL1Staking.json deleted file mode 100644 index 21a217018..000000000 --- a/contracts/abi/archive/legacy-l1-staking/IL1Staking.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChallengeDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChallengeDeposit","type":"uint256"}],"name":"ChallengeDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"GasLimitAddStakerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"GasLimitRemoveStakersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bytes32","name":"tmKey","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"blsKey","type":"bytes"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPercentage","type":"uint256"}],"name":"RewardPercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SlashRemainingClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"Slashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"StakersRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStakingValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStakingValue","type":"uint256"}],"name":"StakingValueUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"add","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"remove","type":"address[]"}],"name":"WhitelistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"unlockHeight","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"challengeDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getActiveStakers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakerBitmap","outputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakers","outputs":[{"internalType":"address[255]","name":"","type":"address[255]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"stakers","type":"address[]"}],"name":"getStakersBitmap","outputs":[{"internalType":"uint256","name":"bitmap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isActiveStaker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isStaker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sequencersBitmap","type":"uint256"}],"name":"slash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"signedSequencersBitmap","type":"uint256"},{"internalType":"address[]","name":"sequencerSet","type":"address[]"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verifySignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/contracts/abi/archive/legacy-l1-staking/L1Staking.json b/contracts/abi/archive/legacy-l1-staking/L1Staking.json deleted file mode 100644 index e8d86b6d8..000000000 --- a/contracts/abi/archive/legacy-l1-staking/L1Staking.json +++ /dev/null @@ -1,1033 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address payable", - "name": "_messenger", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldChallengeDeposit", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newChallengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeDepositUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "staker", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "Claimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldGasLimit", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newGasLimit", - "type": "uint256" - } - ], - "name": "GasLimitAddStakerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldGasLimit", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newGasLimit", - "type": "uint256" - } - ], - "name": "GasLimitRemoveStakersUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "tmKey", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "blsKey", - "type": "bytes" - } - ], - "name": "Registered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercentage", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercentage", - "type": "uint256" - } - ], - "name": "RewardPercentageUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "SlashRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address[]", - "name": "stakers", - "type": "address[]" - } - ], - "name": "Slashed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address[]", - "name": "stakers", - "type": "address[]" - } - ], - "name": "StakersRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldStakingValue", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newStakingValue", - "type": "uint256" - } - ], - "name": "StakingValueUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address[]", - "name": "add", - "type": "address[]" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "remove", - "type": "address[]" - } - ], - "name": "WhitelistUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "unlockHeight", - "type": "uint256" - } - ], - "name": "Withdrawn", - "type": "event" - }, - { - "inputs": [], - "name": "MESSENGER", - "outputs": [ - { - "internalType": "contract ICrossDomainMessenger", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "OTHER_STAKING", - "outputs": [ - { - "internalType": "contract Staking", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "blsPubkey", - "type": "bytes" - } - ], - "name": "blsKeys", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "challengeDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimSlashRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "cleanStakerStore", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "deleteList", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakerAddr", - "type": "address" - } - ], - "name": "deleteableHeight", - "outputs": [ - { - "internalType": "uint256", - "name": "height", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "gasLimitAddStaker", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "gasLimitRemoveStakers", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getActiveStakers", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_staker", - "type": "address" - } - ], - "name": "getStakerBitmap", - "outputs": [ - { - "internalType": "uint256", - "name": "bitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getStakers", - "outputs": [ - { - "internalType": "address[255]", - "name": "", - "type": "address[255]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_stakers", - "type": "address[]" - } - ], - "name": "getStakersBitmap", - "outputs": [ - { - "internalType": "uint256", - "name": "bitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "bitmap", - "type": "uint256" - } - ], - "name": "getStakersFromBitmap", - "outputs": [ - { - "internalType": "address[]", - "name": "stakerAddrs", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_rollupContract", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_stakingValue", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_lockBlocks", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_rewardPercentage", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasLimitAdd", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_gasLimitRemove", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "isActiveStaker", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "isStaker", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "isStakerInDeleteList", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messenger", - "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": "bytes32", - "name": "tmKey", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "blsKey", - "type": "bytes" - } - ], - "name": "register", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_stakers", - "type": "address[]" - } - ], - "name": "removeStaker", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakerAddr", - "type": "address" - } - ], - "name": "removedList", - "outputs": [ - { - "internalType": "bool", - "name": "removed", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "rewardPercentage", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "sequencersBitmap", - "type": "uint256" - } - ], - "name": "slash", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "slashRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakerAddr", - "type": "address" - } - ], - "name": "stakerIndexes", - "outputs": [ - { - "internalType": "uint8", - "name": "index", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "stakerSet", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakerAddr", - "type": "address" - } - ], - "name": "stakers", - "outputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "tmKey", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "blsKey", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stakingValue", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "tmPubkey", - "type": "bytes32" - } - ], - "name": "tmKeys", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_challengeDeposit", - "type": "uint256" - } - ], - "name": "updateChallengeDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_gasLimitAdd", - "type": "uint256" - } - ], - "name": "updateGasLimitAddStaker", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_gasLimitRemove", - "type": "uint256" - } - ], - "name": "updateGasLimitRemoveStakers", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rewardPercentage", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_stakingValue", - "type": "uint256" - } - ], - "name": "updateStakingValue", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "add", - "type": "address[]" - }, - { - "internalType": "address[]", - "name": "remove", - "type": "address[]" - } - ], - "name": "updateWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "", - "type": "address[]" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "verifySignature", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "stakerAddr", - "type": "address" - } - ], - "name": "whitelist", - "outputs": [ - { - "internalType": "bool", - "name": "inWhitelist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawalLockBlocks", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "withdrawals", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/contracts/abi/archive/manifest.json b/contracts/abi/archive/manifest.json deleted file mode 100644 index 1afdd8748..000000000 --- a/contracts/abi/archive/manifest.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "sourceCommit": "3d21e1f45f743b7fb4131fd6655ceb4d99f15356", - "artifacts": { - "pre-submitter/Rollup.json": "aea8c9f75f2c8e132a4ffca3f0bb3f6abd83ae2ae9457827a099e75463c5c03a", - "legacy-l1-staking/IL1Staking.json": "cadf899ad272d9018a3009cd8d5ad4a70760d9a6cddf52de44498f5024ef0ad3", - "legacy-l1-staking/L1Staking.json": "df14c1e4264ba93661b1476ed9166ab06e03d077713fa13b16fded7f1dd6eb46", - "../../storage-layout/archive/Rollup.pre-submitter.json": "f8a745e49d6ea6e141ae26440ce12d6b2feeb155ef1dfdbe9dff40d124c59c37" - }, - "selectors": { - "commitBatch": "0x428868b5", - "commitState": "0x1e8825be", - "commitBatchWithProof": "0x4e8f1d67" - } -} diff --git a/contracts/abi/archive/pre-submitter/Rollup.json b/contracts/abi/archive/pre-submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/contracts/abi/archive/pre-submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/contracts/contracts/Staking.md b/contracts/contracts/Staking.md new file mode 100644 index 000000000..b657c8114 --- /dev/null +++ b/contracts/contracts/Staking.md @@ -0,0 +1,134 @@ +# Staking + +--- + +## Core Process + +**Staking & Sequencer Selection** + +Morph token staking will be divided into three stages: + +- MorphToken has not yet issued yet +- MorphToken has been issued, but inflation and staking rewards have not started yet. +- Inflation starts and distribute staking rewards + +1. `L1` Update whitelist +2. `L1` Register and stake eth to become staker +3. `L1->L2` Send {add staker} message +4. `L2` Update stakers +5. `L2` Delegate stake MorphToken to staker +6. `L2` Update sequencer set by amount of MorphToken delegation + +**Rollp Verify** + +- The submitted batch requires the BLS signature of more than 2/3 of the sequencers +- Before BLS implementation, only staker (not withdrawing, not slashing) can rollup + +1. `L1` Submit batch and sequencer sets +2. `L1` Verify sequencer set +3. `L1` Verify batch signature + +**Slash Sequencers After Challenger Win** + +- Sequencer will be confiscated all stake amount and removed from sequencer set if defense challenge fails +- Even if challenged repeatedly, each sequencer will only be slashed once +- The reward for a successful challenge is a fixed proportion of the staking amount, and is greater than the challenge deposit +- If the slash causes the number of sequences to be 0, then the layer2 will stop running. We can restart by upgrading, reset stakers and sequencer set. This does not affect the security of the evm state + +1. `L1` Slash staking value of signed sequencers and remove from stakers +2. `L1` Distribute challenger rewards +3. `L1->L2` Send {remove stakers} message +4. `L2` Update sequencer set by amount of MorphToken delegation + +**Delegation Rewards** + +- MorphToken is inflated at a fixed ratio every day, and the additional tokens are used as rewards for sequencers and delegators +- The sequencer and his delegators get MorphToken inflation reward according to the block production ratio +- Sequencer charges commission as its own income +- Users get remaining reward according to their delegation amount + +1. `L2` Staker set delegation commission rate +2. `L2` Upload sequencers work records in epoch (an epoch is a day) +3. `L2` Mint MorphToken inflation as delegation reward +4. `L2` Claim delegation reward or claim commission + +**Quit Staker** + +The exit lock period should be long enough to ensure that stakers and sequencers in L2 have been updated + +1. `L1` Apply to withdraw, remove from staker list, enter lock period +2. `L1->L2` Send {remove staker} message +3. `L2` Remove from stakers and sequencers if needed +4. `L1` Claim allowed until reach unlock height,remove staker info after claiming + +--- + +## Contracts + +### L1 Contract + +#### L1Staking Contract + +**Main functions** + +- Update whitelist +- Register as staker +- Staker quit +- Slash signed sequencers if challenger win, call by rollup contract + +#### Rollup Contract + +**Main functions** + +- Commit batch & verify +- Challenge batch + +### L2 Contract + +#### MorphToken Contract + +**Main functions** + +- Mint inflation + +#### Record Contract + +**Main functions** + +- Record finalized batch submissions, call by oracle +- Record rollup epochs, call by oracle +- Record reward epochs, call by oracle + +#### L2Staking Contract + +**Main functions** + +- Add staker, sync from L1 staking contract +- Remove stakers, sync from L1 staking contract +- Staker set commission rate +- User delegate stake morph token +- User undelegate stake morph token +- User claim delegation reward +- Sequencer claim commission + +#### Sequencer Contract + +**Main functions** + +- Update sequencer set, call form l2 staking contract + +#### Distribute Contract + +**Main functions** + +- Record delegation info by l2 staking contract +- Record undelegation info by l2 staking contract +- Compute delegator's delegation reward, call form l2 staking contract +- Compute sequencer's commission, call form l2 staking contract + +#### Gov Contract + +**Main functions** + +- Submit proposal +- Vote proposal diff --git a/contracts/contracts/l1/rollup/BLS.sol b/contracts/contracts/l1/rollup/BLS.sol new file mode 100644 index 000000000..5f78c7036 --- /dev/null +++ b/contracts/contracts/l1/rollup/BLS.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +contract BLS {} diff --git a/contracts/contracts/l1/rollup/IRollup.sol b/contracts/contracts/l1/rollup/IRollup.sol index 1394916d9..d6691cb14 100644 --- a/contracts/contracts/l1/rollup/IRollup.sol +++ b/contracts/contracts/l1/rollup/IRollup.sol @@ -23,15 +23,23 @@ interface IRollup { bytes32 withdrawalRoot; } + /// @param signedSequencers The bitmap of signed sequencers + /// @param sequencerSets The latest 3 sequencer sets + /// @param signature The BLS signature + struct BatchSignatureInput { + uint256 signedSequencersBitmap; + bytes sequencerSets; + bytes signature; + } + /// @param originTimestamp /// @param finalizeTimestamp /// @param blockNumber - /// @param submitter The account responsible for the batch, or zero for permissionless submissions. struct BatchData { uint256 originTimestamp; uint256 finalizeTimestamp; uint256 blockNumber; - address submitter; + uint256 signedSequencersBitmap; } /// @dev Structure to store information about a batch challenge. @@ -120,9 +128,6 @@ interface IRollup { /// @param amount claimed amount. event ProveRemainingClaimed(address receiver, uint256 amount); - /// @notice Emitted when the legacy staking dependency is replaced with Submitter. - event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr); - /// @notice Emitted when the state of Challenge is updated. /// @param batchIndex The index of the batch. /// @param challenger The address of challenger. @@ -169,30 +174,36 @@ interface IRollup { /// @notice Return the rollup config of finalizationPeriodSeconds. function finalizationPeriodSeconds() external view returns (uint256); - /// @notice Number of committed, non-terminated batches attributable to a submitter. - function pendingBatchCount(address submitter) external view returns (uint256); - /***************************** * Public Mutating Functions * *****************************/ /// @notice Commit a batch of transactions on layer 1. /// - /// @param batchDataInput The BatchDataInput struct - function commitBatch(BatchDataInput calldata batchDataInput) external payable; + /// @param batchDataInput The BatchDataInput struct + /// @param batchSignatureInput The BatchSignatureInput struct + function commitBatch( + BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput + ) external payable; /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). /// @dev Requires batchBlobVersionedHashes[nextBatchIndex] != 0. - function commitState(BatchDataInput calldata batchDataInput) external; + function commitState( + BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput + ) external; /// @notice Commit a batch with ZKP proof for permissionless submission. /// @dev This function allows anyone to submit batches when the sequencer is offline or censoring. /// - /// @param batchDataInput The BatchDataInput struct - /// @param batchHeader The batch header for ZKP verification - /// @param batchProof The ZKP proof data + /// @param batchDataInput The BatchDataInput struct + /// @param batchSignatureInput The BatchSignatureInput struct + /// @param batchHeader The batch header for ZKP verification + /// @param batchProof The ZKP proof data function commitBatchWithProof( BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput, bytes calldata batchHeader, bytes calldata batchProof ) external; diff --git a/contracts/contracts/l1/rollup/ISubmitter.sol b/contracts/contracts/l1/rollup/ISubmitter.sol deleted file mode 100644 index 57747a235..000000000 --- a/contracts/contracts/l1/rollup/ISubmitter.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -/// @notice Runtime interface used by Rollup after the centralized submitter cutover. -interface ISubmitter { - function rollupContract() external view returns (address); - - function isActive(address submitter) external view returns (bool); - - function challengeDeposit() external view returns (uint256); - - function slash(address submitter) external returns (uint256 reward); -} - -/// @notice Bounded liability view used by Submitter before releasing stake. -interface IRollupSubmitterView { - function pendingBatchCount(address submitter) external view returns (uint256); -} diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 77d80454a..14aae181b 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -9,7 +9,7 @@ import {BatchHeaderCodecV1} from "../../libraries/codec/BatchHeaderCodecV1.sol"; import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol"; import {IL1MessageQueue} from "./IL1MessageQueue.sol"; import {IRollup} from "./IRollup.sol"; -import {ISubmitter} from "./ISubmitter.sol"; +import {IL1Staking} from "../staking/IL1Staking.sol"; // solhint-disable no-inline-assembly // solhint-disable reason-string @@ -24,6 +24,13 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice The zero versioned hash. bytes32 internal constant ZERO_VERSIONED_HASH = 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014; + /// @notice The BLS MODULUS. Deprecated. + uint256 internal constant __BLS_MODULUS = + 52435875175126190479447740508185965837690552500527637822603658699938581184513; + + /// @dev Address of the point evaluation precompile used for EIP-4844 blob verification. + address internal constant POINT_EVALUATION_PRECOMPILE_ADDR = address(0x0A); + /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable LAYER_2_CHAIN_ID; @@ -31,9 +38,8 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { * Variables * *************/ - /// @notice Submitter registration and staking contract. - /// @dev Occupies the legacy staking dependency's storage slot. - address public submitterContract; + /// @notice L1 staking contract + address public l1StakingContract; /// @notice Batch challenge time. uint256 public finalizationPeriodSeconds; @@ -103,16 +109,13 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Placed after rollupDelayPeriod for upgrade-safe storage layout (forward compatibility). mapping(uint256 batchIndex => bytes32 blobVersionedHash) public batchBlobVersionedHashes; - /// @inheritdoc IRollup - mapping(address submitter => uint256 count) public override pendingBatchCount; - /********************** * Function Modifiers * **********************/ - /// @notice Only an active submitter is allowed. - modifier onlyActiveSubmitter() { - require(ISubmitter(submitterContract).isActive(_msgSender()), "only active submitter allowed"); + /// @notice Only active staker allowed. + modifier onlyActiveStaker() { + require(IL1Staking(l1StakingContract).isActiveStaker(_msgSender()), "only active staker allowed"); _; } @@ -147,13 +150,13 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ***************/ /// @notice initializer - /// @param _submitterContract submitter contract + /// @param _l1StakingContract l1 staking contract /// @param _messageQueue message queue /// @param _verifier verifier /// @param _finalizationPeriodSeconds finalization period seconds /// @param _proofWindow proof window function initialize( - address _submitterContract, + address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, @@ -163,12 +166,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (_messageQueue == address(0) || _verifier == address(0)) { revert ErrZeroAddress(); } - require(_submitterContract != address(0), "invalid submitter contract"); + require(_l1StakingContract != address(0), "invalid l1 staking contract"); __Pausable_init(); __Ownable_init(); - submitterContract = _submitterContract; + l1StakingContract = _l1StakingContract; messageQueue = _messageQueue; verifier = _verifier; finalizationPeriodSeconds = _finalizationPeriodSeconds; @@ -180,7 +183,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { emit UpdateProofRewardPercent(0, _proofRewardPercent); } - function initialize2(bytes32 _prevStateRoot) external reinitializer(2) onlyOwner { + function initialize2(bytes32 _prevStateRoot) external reinitializer(2) { require(_getInitializedVersion() == 2, "must have initialized!"); require(_prevStateRoot != bytes32(0), "can not set state root with bytes32(0)!"); @@ -191,42 +194,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice Initializer for upgrade to version 3. /// @param _rollupDelayPeriod The delay period for permissionless batch submission. - function initialize3(uint256 _rollupDelayPeriod) external reinitializer(3) onlyOwner { + function initialize3(uint256 _rollupDelayPeriod) external reinitializer(3) { require(_rollupDelayPeriod != 0, "invalid rollup delay period"); rollupDelayPeriod = _rollupDelayPeriod; emit UpdateRollupDelayPeriod(0, _rollupDelayPeriod); } - /// @notice One-time cutover from the legacy staking address to the Submitter proxy. - /// @dev The cutover is deliberately gated by an empty pending-batch tail, not by pause state. - function initialize4(address _newSubmitter) external reinitializer(4) onlyOwner { - require(_newSubmitter != address(0) && _newSubmitter.code.length > 0, "invalid submitter"); - - bytes32 _declaredRollupRaw = _staticcallExact32( - _newSubmitter, - abi.encodeCall(ISubmitter.rollupContract, ()) - ); - require(uint256(_declaredRollupRaw) >> 160 == 0, "invalid rollup encoding"); - address _declaredRollup = address(uint160(uint256(_declaredRollupRaw))); - uint256 _zeroAddressActive = uint256( - _staticcallExact32(_newSubmitter, abi.encodeCall(ISubmitter.isActive, (address(0)))) - ); - uint256 _challengeDeposit = uint256( - _staticcallExact32(_newSubmitter, abi.encodeCall(ISubmitter.challengeDeposit, ())) - ); - - require(_declaredRollup == address(this), "submitter rollup mismatch"); - require(_zeroAddressActive == 0 && _challengeDeposit > 0, "invalid submitter state"); - require(lastCommittedBatchIndex == lastFinalizedBatchIndex, "pending batches"); - require(revertReqIndex == 0, "pending revert request"); - - // The last finalized entry survives normal GC. Clear only the legacy bitmap slot so it - // cannot be interpreted as a submitter address after the storage-compatible type change. - batchDataStore[lastFinalizedBatchIndex].submitter = address(0); - emit SubmitterContractUpdated(submitterContract, _newSubmitter); - submitterContract = _newSubmitter; - } - /************************ * Restricted Functions * ************************/ @@ -248,7 +221,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { require(BatchHeaderCodecV0.getBlobVersionedHash(memPtr) == ZERO_VERSIONED_HASH, "invalid versioned hash"); committedBatches[_batchIndex] = _batchHash; - batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, address(0)); + batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, 0); batchBlobVersionedHashes[_batchIndex] = BatchHeaderCodecV0.getBlobVersionedHash(memPtr); committedStateRoots[_batchIndex] = _postStateRoot; @@ -262,23 +235,29 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @inheritdoc IRollup function commitBatch( - BatchDataInput calldata batchDataInput - ) external payable override onlyActiveSubmitter nonReqRevert whenNotPaused { - require(blobhash(0) != bytes32(0), "must carry blob"); + BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput + ) external payable override onlyActiveStaker nonReqRevert whenNotPaused { + // check if the next batch has a stored blob hash + (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); + uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; + require(batchBlobVersionedHashes[_nextBatchIndex] == bytes32(0), "commitBatch requires no stored blob hash"); if ( IL1MessageQueue(messageQueue).getFirstUnfinalizedMessageEnqueueTime() + rollupDelayPeriod < block.timestamp ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } + uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); bytes32 _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); - _commitBatchWithBatchData(batchDataInput, _msgSender(), _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, batchSignatureInput, submitterBitmap, _blobVersionedHash); } /// @inheritdoc IRollup /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). function commitState( - BatchDataInput calldata batchDataInput - ) external override onlyActiveSubmitter nonReqRevert whenNotPaused { + BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput + ) external override onlyActiveStaker nonReqRevert whenNotPaused { require(blobhash(0) == bytes32(0), "commitState must not carry blob"); (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; @@ -288,12 +267,19 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - _commitBatchWithBatchData(batchDataInput, _msgSender(), batchBlobVersionedHashes[_nextBatchIndex]); + uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); + _commitBatchWithBatchData( + batchDataInput, + batchSignatureInput, + submitterBitmap, + batchBlobVersionedHashes[_nextBatchIndex] + ); } function _commitBatchWithBatchData( BatchDataInput calldata batchDataInput, - address submitter, + BatchSignatureInput calldata batchSignatureInput, + uint256 submitterBitmap, bytes32 blobVersionedHash ) internal { require(batchDataInput.version <= 2, "invalid version"); @@ -354,7 +340,10 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { BatchHeaderCodecV0.storePrevStateHash(_batchPtr, batchDataInput.prevStateRoot); BatchHeaderCodecV0.storePostStateHash(_batchPtr, batchDataInput.postStateRoot); BatchHeaderCodecV0.storeWithdrawRootHash(_batchPtr, batchDataInput.withdrawalRoot); - BatchHeaderCodecV0.storeSequencerSetVerifyHash(_batchPtr, bytes32(0)); + BatchHeaderCodecV0.storeSequencerSetVerifyHash( + _batchPtr, + keccak256(batchSignatureInput.sequencerSets) + ); BatchHeaderCodecV0.storeParentBatchHash(_batchPtr, _parentBatchHash); if (batchDataInput.version >= 1) { BatchHeaderCodecV1.storeLastBlockNumber(_batchPtr, batchDataInput.lastBlockNumber); @@ -373,12 +362,24 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { block.timestamp, block.timestamp + finalizationPeriodSeconds + proveRemainingTime, batchDataInput.lastBlockNumber, - submitter + // Before BLS is implemented, the accuracy of the sequencer set uploaded by rollup cannot be guaranteed. + // Therefore, if the batch is successfully challenged, only the submitter will be punished. + submitterBitmap // => batchSignature.signedSequencersBitmap ); - _increaseLiability(submitter); lastCommittedBatchIndex = _batchIndex; } + + // verify bls signature + require( + IL1Staking(l1StakingContract).verifySignature( + batchSignatureInput.signedSequencersBitmap, + _getValidSequencerSet(batchSignatureInput.sequencerSets, 0), + _getBLSMsgHash(batchDataInput), + batchSignatureInput.signature + ), + "the signature verification failed" + ); emit CommitBatch(_batchIndex, committedBatches[_batchIndex]); } @@ -387,6 +388,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// Entry conditions: rollup delay OR L1 message queue delay must be met. function commitBatchWithProof( BatchDataInput calldata batchDataInput, + BatchSignatureInput calldata batchSignatureInput, bytes calldata _batchHeader, bytes calldata _batchProof ) external override nonReqRevert whenNotPaused { @@ -414,7 +416,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { } else { _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); } - _commitBatchWithBatchData(batchDataInput, address(0), _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, batchSignatureInput, 0, _blobVersionedHash); // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); @@ -450,7 +452,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { while (_count > 0) { emit RevertBatch(_batchIndex, _batchHash); - _releaseLiability(_batchIndex); committedBatches[_batchIndex] = bytes32(0); // if challenge exist and not finished yet, return challenge deposit to challenger if (batchInChallenge(_batchIndex)) { @@ -487,7 +488,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { // check challenge window require(batchInsideChallengeWindow(batchIndex), "cannot challenge batch outside the challenge window"); // check challenge amount - require(msg.value >= ISubmitter(submitterContract).challengeDeposit(), "insufficient value"); + require(msg.value >= IL1Staking(l1StakingContract).challengeDeposit(), "insufficient value"); batchChallenged = batchIndex; challenges[batchIndex] = BatchChallenge(batchIndex, _msgSender(), msg.value, block.timestamp, false, false); @@ -602,7 +603,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { function proveState( bytes calldata _batchHeader, bytes calldata _batchProof - ) external nonReqRevert whenNotPaused onlyActiveSubmitter { + ) external nonReqRevert whenNotPaused onlyActiveStaker { // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); // check batch hash @@ -620,7 +621,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (challenges[_batchIndex].startTime + proofWindow <= block.timestamp) { // set status challenges[_batchIndex].challengeSuccess = true; - _challengerWin(_batchIndex, batchDataStore[_batchIndex].submitter, "Timeout"); + _challengerWin(_batchIndex, batchDataStore[_batchIndex].signedSequencersBitmap, "Timeout"); } else { _verifyProof(memPtr, _batchProof); // Record defender win @@ -661,7 +662,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { BatchHeaderCodecV0.getL1MessagePopped(memPtr) ); - _releaseLiability(_batchIndex); delete batchDataStore[_batchIndex - 1]; delete committedStateRoots[_batchIndex - 1]; delete batchBlobVersionedHashes[_batchIndex - 1]; @@ -784,6 +784,37 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ); } + /// @dev Internal function to compute BLS msg hash + function _getBLSMsgHash( + BatchDataInput calldata // batchDataInput + ) internal pure returns (bytes32) { + // TODO compute bls message hash + return bytes32(0); + } + + /// @dev todo + function _getValidSequencerSet( + bytes calldata sequencerSets, + uint256 blockHeight + ) internal pure returns (address[] memory) { + // TODO require submitter was in valid sequencer set after BLS was implemented + ( + , + address[] memory sequencerSet0, + uint256 blockHeight1, + address[] memory sequencerSet1, + uint256 blockHeight2, + address[] memory sequencerSet2 + ) = abi.decode(sequencerSets, (uint256, address[], uint256, address[], uint256, address[])); + if (blockHeight >= blockHeight2) { + return sequencerSet2; + } + if (blockHeight >= blockHeight1) { + return sequencerSet1; + } + return sequencerSet0; + } + /// @dev Internal function executed when the defender wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. /// @param prover The zkProof prover address. @@ -798,44 +829,16 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Internal function executed when the challenger wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. - /// @param submitter The account responsible for the challenged batch. + /// @param sequencersBitmap An array containing the sequencers to be slashed. /// @param _type Description of the challenge type. - function _challengerWin(uint256 batchIndex, address submitter, string memory _type) internal { + function _challengerWin(uint256 batchIndex, uint256 sequencersBitmap, string memory _type) internal { revertReqIndex = batchIndex; address challenger = challenges[batchIndex].challenger; - uint256 reward = ISubmitter(submitterContract).slash(submitter); + uint256 reward = IL1Staking(l1StakingContract).slash(sequencersBitmap); batchChallengeReward[challenges[batchIndex].challenger] += (challenges[batchIndex].challengeDeposit + reward); emit ChallengeRes(batchIndex, challenger, _type); } - function _increaseLiability(address submitter) internal { - if (submitter != address(0)) { - pendingBatchCount[submitter] += 1; - } - } - - function _releaseLiability(uint256 batchIndex) internal { - address liable = batchDataStore[batchIndex].submitter; - if (liable == address(0)) return; - uint256 count = pendingBatchCount[liable]; - require(count > 0, "pending batch count underflow"); - pendingBatchCount[liable] = count - 1; - } - - function _staticcallExact32(address target, bytes memory input) internal view returns (bytes32 result) { - bool ok; - uint256 size; - assembly ("memory-safe") { - ok := staticcall(gas(), target, add(input, 0x20), mload(input), 0, 0) - size := returndatasize() - if and(ok, eq(size, 0x20)) { - returndatacopy(0, 0, 0x20) - result := mload(0) - } - } - require(ok && size == 32, "invalid submitter interface"); - } - /// @dev Internal function to transfer ETH to a specified address. /// @param _to The address to transfer ETH to. /// @param _amount The amount of ETH to transfer. diff --git a/contracts/contracts/l1/rollup/Submitter.sol b/contracts/contracts/l1/rollup/Submitter.sol deleted file mode 100644 index 0ed52cf4a..000000000 --- a/contracts/contracts/l1/rollup/Submitter.sol +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; - -import {IRollupSubmitterView, ISubmitter} from "./ISubmitter.sol"; - -/// @title Submitter -/// @notice Registration, stake, exit, and slashing for centralized batch submitters. -contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable { - uint256 internal constant LIABILITY_QUERY_GAS_LIMIT = 50_000; - uint256 internal constant REFUND_GAS_LIMIT = 50_000; - - address public override rollupContract; - uint256 public minimumStake; - uint256 public override challengeDeposit; - uint256 public rewardPercentage; - uint256 public slashRemaining; - - mapping(address submitter => bool isRegistered) public registered; - mapping(address submitter => uint256 amount) public stakeOf; - mapping(address submitter => bool isExiting) public exiting; - mapping(address submitter => uint256 amount) public claimable; - - event SubmitterAdded(address indexed submitter); - event SubmitterRemoved(address indexed submitter); - event MinimumStakeUpdated(uint256 oldValue, uint256 newValue); - event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue); - event RewardPercentageUpdated(uint256 oldValue, uint256 newValue); - event Staked(address indexed submitter, uint256 amount, uint256 total); - event WithdrawalRequested(address indexed submitter, address indexed receiver, uint256 amount); - event WithdrawalPaid(address indexed submitter, address indexed receiver, uint256 amount); - event WithdrawalCredited(address indexed submitter, uint256 amount, uint256 totalCredit); - event CreditClaimed(address indexed submitter, address indexed receiver, uint256 amount); - event Slashed(address indexed submitter, uint256 amount, uint256 reward); - event SlashRemainingClaimed(address indexed receiver, uint256 amount); - - modifier onlyRollup() { - require(_msgSender() == rollupContract, "only rollup contract"); - _; - } - - constructor() { - _disableInitializers(); - } - - function initialize( - address owner_, - address rollupContract_, - uint256 minimumStake_, - uint256 challengeDeposit_, - uint256 rewardPercentage_ - ) external initializer { - require(owner_ != address(0), "invalid owner"); - require(rollupContract_ != address(0) && rollupContract_.code.length > 0, "invalid rollup contract"); - require(minimumStake_ > 0, "invalid minimum stake"); - require(challengeDeposit_ > 0, "invalid challenge deposit"); - require(rewardPercentage_ > 0 && rewardPercentage_ <= 100, "invalid reward percentage"); - - __Ownable_init(); - __ReentrancyGuard_init(); - _transferOwnership(owner_); - - rollupContract = rollupContract_; - minimumStake = minimumStake_; - challengeDeposit = challengeDeposit_; - rewardPercentage = rewardPercentage_; - - emit MinimumStakeUpdated(0, minimumStake_); - emit ChallengeDepositUpdated(0, challengeDeposit_); - emit RewardPercentageUpdated(0, rewardPercentage_); - } - - function isActive(address submitter) public view override returns (bool) { - return registered[submitter] && !exiting[submitter] && stakeOf[submitter] >= minimumStake; - } - - function addSubmitter(address submitter) external onlyOwner { - require(submitter != address(0) && !registered[submitter] && !exiting[submitter], "invalid submitter"); - registered[submitter] = true; - emit SubmitterAdded(submitter); - } - - function removeSubmitter(address submitter) external onlyOwner nonReentrant { - require(registered[submitter] && !exiting[submitter], "invalid submitter"); - registered[submitter] = false; - exiting[submitter] = true; - emit SubmitterRemoved(submitter); - emit WithdrawalRequested(submitter, submitter, stakeOf[submitter]); - _settleIfReleased(submitter, submitter); - } - - function setMinimumStake(uint256 value) external onlyOwner { - require(value > 0 && value != minimumStake, "invalid minimum stake"); - emit MinimumStakeUpdated(minimumStake, value); - minimumStake = value; - } - - function updateChallengeDeposit(uint256 value) external onlyOwner { - require(value > 0 && value != challengeDeposit, "invalid challenge deposit"); - emit ChallengeDepositUpdated(challengeDeposit, value); - challengeDeposit = value; - } - - function updateRewardPercentage(uint256 value) external onlyOwner { - require(value > 0 && value <= 100 && value != rewardPercentage, "invalid reward percentage"); - emit RewardPercentageUpdated(rewardPercentage, value); - rewardPercentage = value; - } - - function stake() external payable nonReentrant { - address submitter = _msgSender(); - require(registered[submitter] && !exiting[submitter], "not stakeable"); - uint256 total = stakeOf[submitter] + msg.value; - require(msg.value > 0 && total >= minimumStake, "below minimum stake"); - stakeOf[submitter] = total; - emit Staked(submitter, msg.value, total); - } - - function withdraw(address receiver) external nonReentrant { - address submitter = _msgSender(); - require(receiver != address(0), "invalid receiver"); - require(registered[submitter] && !exiting[submitter] && stakeOf[submitter] > 0, "not withdrawable"); - - // A completed exit always requires a fresh owner registration before staking again. - registered[submitter] = false; - exiting[submitter] = true; - emit WithdrawalRequested(submitter, receiver, stakeOf[submitter]); - _settleIfReleased(submitter, receiver); - } - - function claimWithdrawal(address receiver) external nonReentrant { - address submitter = _msgSender(); - require(receiver != address(0), "invalid receiver"); - require(exiting[submitter], "not exiting"); - require(_liabilityReleased(submitter), "pending batch liability"); - _settle(submitter, receiver); - } - - function claimCredit(address receiver) external nonReentrant { - address submitter = _msgSender(); - require(receiver != address(0), "invalid receiver"); - uint256 amount = claimable[submitter]; - require(amount > 0, "no credit"); - claimable[submitter] = 0; - _transfer(receiver, amount); - emit CreditClaimed(submitter, receiver, amount); - } - - function slash(address submitter) external override onlyRollup nonReentrant returns (uint256 reward) { - if (submitter == address(0)) return 0; - - uint256 amount = stakeOf[submitter]; - registered[submitter] = false; - stakeOf[submitter] = 0; - exiting[submitter] = true; - - reward = (amount * rewardPercentage) / 100; - slashRemaining += amount - reward; - _transfer(rollupContract, reward); - emit Slashed(submitter, amount, reward); - } - - function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { - require(receiver != address(0), "invalid receiver"); - uint256 amount = slashRemaining; - require(amount > 0, "no slash remaining"); - slashRemaining = 0; - _transfer(receiver, amount); - emit SlashRemainingClaimed(receiver, amount); - } - - function _settleIfReleased(address submitter, address receiver) internal { - if (_liabilityReleased(submitter)) _settle(submitter, receiver); - } - - function _settle(address submitter, address receiver) internal { - uint256 amount = stakeOf[submitter]; - stakeOf[submitter] = 0; - exiting[submitter] = false; - - if (amount == 0) { - emit WithdrawalPaid(submitter, receiver, 0); - return; - } - - (bool success,) = receiver.call{value: amount, gas: REFUND_GAS_LIMIT}(""); - if (success) { - emit WithdrawalPaid(submitter, receiver, amount); - } else { - claimable[submitter] += amount; - emit WithdrawalCredited(submitter, amount, claimable[submitter]); - } - } - - function _liabilityReleased(address submitter) internal view returns (bool) { - bytes memory input = abi.encodeCall(IRollupSubmitterView.pendingBatchCount, (submitter)); - address target = rollupContract; - bool ok; - uint256 size; - uint256 count; - assembly ("memory-safe") { - ok := staticcall(LIABILITY_QUERY_GAS_LIMIT, target, add(input, 0x20), mload(input), 0, 0) - size := returndatasize() - if and(ok, eq(size, 0x20)) { - returndatacopy(0, 0, 0x20) - count := mload(0) - } - } - return ok && size == 32 && count == 0; - } - - function _transfer(address receiver, uint256 amount) internal { - if (amount == 0) return; - (bool success,) = receiver.call{value: amount}(""); - require(success, "ETH transfer failed"); - } - - uint256[50] private __gap; -} diff --git a/contracts/contracts/l1/staking/IL1Staking.sol b/contracts/contracts/l1/staking/IL1Staking.sol new file mode 100644 index 000000000..ba4f6801b --- /dev/null +++ b/contracts/contracts/l1/staking/IL1Staking.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +interface IL1Staking { + /********** + * Events * + **********/ + + /// @notice staker registered + /// @param addr staker address + /// @param tmKey tendermint pubkey + /// @param blsKey BLS pubkey + event Registered(address addr, bytes32 tmKey, bytes blsKey); + + /// @notice stakers removed + /// @param stakers stakers removed + event StakersRemoved(address[] stakers); + + /// @notice Withdrawn + /// @param addr staker address + /// @param unlockHeight unlock block height + event Withdrawn(address indexed addr, uint256 unlockHeight); + + /// @notice staker claimed + /// @param staker staker claimed + /// @param receiver receiver address + event Claimed(address indexed staker, address receiver); + + /// @notice stakers were slashed + /// @param stakers slashed stakers + event Slashed(address[] stakers); + + /// @notice slash remaining claimed + /// @param receiver receiver address + /// @param amount claimed amount + event SlashRemainingClaimed(address receiver, uint256 amount); + + /// @notice whitelist updated + /// @param add addresses added + /// @param remove addresses removed + event WhitelistUpdated(address[] add, address[] remove); + + /// @notice staking value updated + /// @param oldStakingValue old staking value + /// @param newStakingValue new staking value + event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue); + + /// @notice gas limit add staker updated + /// @param oldGasLimit old gas limit + /// @param newGasLimit new gas limit + event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit); + + /// @notice gas limit remove stakers updated + /// @param oldGasLimit old gas limit + /// @param newGasLimit new gas limit + event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit); + + /// @notice reward percentage updated + /// @param oldPercentage old percentage + /// @param newPercentage new percentage + event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage); + + /// @notice challenge deposit value updated + /// @param oldChallengeDeposit old challengeDeposit + /// @param newChallengeDeposit new challengeDeposit + event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit); + + /************************* + * Public View Functions * + *************************/ + + /// @notice return all stakers + function getStakers() external view returns (address[255] memory); + + /// @notice return active stakers + function getActiveStakers() external view returns (address[] memory); + + /// @notice return staking value + function stakingValue() external view returns (uint256); + + /// @notice return challenge deposit value + function challengeDeposit() external view returns (uint256); + + /// @notice whether address is staker + /// @param addr the address to check + function isStaker(address addr) external view returns (bool); + + /// @notice whether address is active staker + /// @param addr the address to check + function isActiveStaker(address addr) external view returns (bool); + + /// @notice get staker bitmap + /// @param staker the staker address + function getStakerBitmap(address staker) external view returns (uint256); + + /// @notice get stakers bitmap + /// @param stakers the staker address array + function getStakersBitmap(address[] calldata stakers) external view returns (uint256); + + /// @notice verify BLS signature + /// @param signedSequencersBitmap bitmap of signed sequencers + /// @param sequencerSet sequencer set + /// @param msgHash bls message hash + /// @param signature batch signature + function verifySignature( + uint256 signedSequencersBitmap, + address[] calldata sequencerSet, + bytes32 msgHash, + bytes calldata signature + ) external view returns (bool); + + /***************************** + * Public Mutating Functions * + *****************************/ + + /// @notice challenger win, slash sequencers + /// @param sequencersBitmap the sequencers to slash + function slash(uint256 sequencersBitmap) external returns (uint256); +} diff --git a/contracts/contracts/l1/staking/L1Staking.sol b/contracts/contracts/l1/staking/L1Staking.sol new file mode 100644 index 000000000..165fec18d --- /dev/null +++ b/contracts/contracts/l1/staking/L1Staking.sol @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; + +import {Predeploys} from "../../libraries/constants/Predeploys.sol"; +import {Types} from "../../libraries/common/Types.sol"; +import {Staking} from "../../libraries/staking/Staking.sol"; +import {IL1Staking} from "./IL1Staking.sol"; +import {IL2Staking} from "../../l2/staking/IL2Staking.sol"; + +contract L1Staking is IL1Staking, Staking, OwnableUpgradeable, ReentrancyGuardUpgradeable { + /************* + * Variables * + *************/ + + /// @notice rollup Contract + address public rollupContract; + + /// @notice staking value + uint256 public stakingValue; + + /// @notice exit lock blocks + uint256 public withdrawalLockBlocks; + + /// @notice percentage awarded to challenger + uint256 public rewardPercentage; + + /// @notice cross-chain gas limit add staker + uint256 public gasLimitAddStaker; + + /// @notice cross-chain gas limit remove stakers + uint256 public gasLimitRemoveStakers; + + /// @notice slash remaining + uint256 public slashRemaining; + + /// @notice staker whitelist + mapping(address stakerAddr => bool inWhitelist) public whitelist; + + /// @notice staker removed list + mapping(address stakerAddr => bool removed) public removedList; + + /// @notice all stakers (0-254) + address[255] public stakerSet; + + /// @notice all stakers indexes (1-255). '0' means not exist. stakerIndexes[1] releated to stakerSet[0] + mapping(address stakerAddr => uint8 index) public stakerIndexes; + + /// @notice stakers to delete + address[] public deleteList; + + /// @notice staker deleteable height + mapping(address stakerAddr => uint256 height) public deleteableHeight; + + /// @notice all stakers info + mapping(address stakerAddr => Types.StakerInfo) public stakers; + + /// @notice bls key map + mapping(bytes blsPubkey => bool exist) public blsKeys; + + /// @notice tendermint key map + mapping(bytes32 tmPubkey => bool exist) public tmKeys; + + /// @notice withdraw unlock block height + mapping(address staker => uint256 amount) public withdrawals; + + /// @notice challenge deposit value + uint256 public challengeDeposit; + + /********************** + * Function Modifiers * + **********************/ + + /// @notice whether in whitelist + modifier inWhitelist(address addr) { + require(whitelist[addr], "not in whitelist"); + _; + } + + /// @notice only rollup contract + modifier onlyRollupContract() { + require(_msgSender() == rollupContract, "only rollup contract"); + _; + } + + /*************** + * Constructor * + ***************/ + + /// @param _messenger Address of CrossDomainMessenger on this network. + constructor(address payable _messenger) Staking(_messenger, payable(Predeploys.L2_STAKING)) { + _disableInitializers(); + } + + /*************** + * Initializer * + ***************/ + + /// @notice initializer + /// @param _rollupContract rollup contract address + /// @param _stakingValue staking value + /// @param _challengeDeposit challenge deposit value + /// @param _lockBlocks withdraw lock blocks + /// @param _rewardPercentage percentage awarded to challenger + /// @param _gasLimitAdd cross-chain gas limit add staker + /// @param _gasLimitRemove cross-chain gas limit remove stakers + function initialize( + address _rollupContract, + uint256 _stakingValue, + uint256 _challengeDeposit, + uint256 _lockBlocks, + uint256 _rewardPercentage, + uint256 _gasLimitAdd, + uint256 _gasLimitRemove + ) public initializer { + require(_rollupContract != address(0), "invalid rollup contract"); + require(_stakingValue > 0, "invalid staking value"); + require(_challengeDeposit > 0, "invalid challenge deposit value"); + require(_lockBlocks > 0, "invalid withdrawal lock blocks"); + require(_gasLimitAdd > 0, "invalid gas limit add staker"); + require(_gasLimitRemove > 0, "invalid gas limit remove stakers"); + require(_rewardPercentage > 0 && _rewardPercentage <= 100, "invalid challenger reward percentage"); + + __Ownable_init(); + __ReentrancyGuard_init(); + + rollupContract = _rollupContract; + rewardPercentage = _rewardPercentage; + stakingValue = _stakingValue; + challengeDeposit = _challengeDeposit; + withdrawalLockBlocks = _lockBlocks; + gasLimitAddStaker = _gasLimitAdd; + gasLimitRemoveStakers = _gasLimitRemove; + + emit GasLimitAddStakerUpdated(0, _gasLimitAdd); + emit GasLimitRemoveStakersUpdated(0, _gasLimitRemove); + emit RewardPercentageUpdated(0, _rewardPercentage); + } + + /************************ + * Restricted Functions * + ************************/ + + /// @notice update whitelist + function updateWhitelist(address[] calldata add, address[] calldata remove) external onlyOwner { + for (uint256 i = 0; i < add.length; i++) { + require(!removedList[add[i]], "in removed list"); + whitelist[add[i]] = true; + } + for (uint256 i = 0; i < remove.length; i++) { + delete whitelist[remove[i]]; + } + emit WhitelistUpdated(add, remove); + } + + /// @notice register staker + /// @param tmKey tendermint pubkey + /// @param blsKey bls pubkey + function register(bytes32 tmKey, bytes memory blsKey) external payable inWhitelist(_msgSender()) { + require(stakers[_msgSender()].addr == address(0), "already registered"); + require(tmKey != 0 && !tmKeys[tmKey], "invalid tendermint pubkey"); + require(blsKey.length == 256 && !blsKeys[blsKey], "invalid bls pubkey"); + require(msg.value == stakingValue, "invalid staking value"); + + stakers[_msgSender()] = Types.StakerInfo(_msgSender(), tmKey, blsKey); + _addStaker(_msgSender()); + blsKeys[blsKey] = true; + tmKeys[tmKey] = true; + emit Registered(_msgSender(), tmKey, blsKey); + + // send message to add staker on l2 + _msgAddStaker(stakers[_msgSender()]); + } + + /// @notice remove staker + function removeStaker(address[] memory _stakers) external onlyOwner { + for (uint256 i = 0; i < _stakers.length; i++) { + require(isActiveStaker(_stakers[i]), "only active staker can be removed"); + require(withdrawals[_stakers[i]] == 0, "withdrawing"); + + withdrawals[_stakers[i]] = block.number + withdrawalLockBlocks; + _removeStaker(_stakers[i]); + emit Withdrawn(_stakers[i], withdrawals[_stakers[i]]); + + delete whitelist[_stakers[i]]; + removedList[_stakers[i]] = true; + } + emit StakersRemoved(_stakers); + + // send message to remove stakers on l2 + _msgRemoveStakers(_stakers); + } + + /// @notice withdraw staking + function withdraw() external { + require(isActiveStaker(_msgSender()), "only active staker"); + require(withdrawals[_msgSender()] == 0, "withdrawing"); + + withdrawals[_msgSender()] = block.number + withdrawalLockBlocks; + _removeStaker(_msgSender()); + emit Withdrawn(_msgSender(), withdrawals[_msgSender()]); + + delete whitelist[_msgSender()]; + removedList[_msgSender()] = true; + + address[] memory remove = new address[](1); + remove[0] = _msgSender(); + emit StakersRemoved(remove); + + // send message to remove staker on l2 + _msgRemoveStakers(remove); + } + + /// @notice challenger win, slash sequencers + function slash(uint256 sequencersBitmap) external onlyRollupContract nonReentrant returns (uint256) { + address[] memory sequencers = getStakersFromBitmap(sequencersBitmap); + + uint256 valueSum; + for (uint256 i = 0; i < sequencers.length; i++) { + if (withdrawals[sequencers[i]] > 0) { + delete withdrawals[sequencers[i]]; + valueSum += stakingValue; + } else if (!isStakerInDeleteList(sequencers[i])) { + // If it is the first time to be slashed + valueSum += stakingValue; + _removeStaker(sequencers[i]); + // remove from whitelist + delete whitelist[sequencers[i]]; + removedList[sequencers[i]] = true; + } + } + + uint256 reward = (valueSum * rewardPercentage) / 100; + slashRemaining += valueSum - reward; + _transfer(rollupContract, reward); + + emit Slashed(sequencers); + emit StakersRemoved(sequencers); + + // send message to remove stakers on l2 + _msgRemoveStakers(sequencers); + + return reward; + } + + /// @notice claim slash remaining + /// @param receiver receiver address + function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { + uint256 _slashRemaining = slashRemaining; + _transfer(receiver, slashRemaining); + slashRemaining = 0; + emit SlashRemainingClaimed(receiver, _slashRemaining); + } + + /// @notice update staking value + /// @param _stakingValue staking value + function updateStakingValue(uint256 _stakingValue) external onlyOwner { + require(_stakingValue > 0 && _stakingValue != stakingValue, "invalid staking value"); + uint256 _oldStakingValue = stakingValue; + stakingValue = _stakingValue; + emit StakingValueUpdated(_oldStakingValue, stakingValue); + } + + /// @notice update gas limit of add staker + /// @param _gasLimitAdd cross-chain gas limit add staker + function updateGasLimitAddStaker(uint256 _gasLimitAdd) external onlyOwner { + require(_gasLimitAdd > 0 && _gasLimitAdd != gasLimitAddStaker, "invalid new gas limit"); + uint256 _oldGasLimitAddStaker = gasLimitAddStaker; + gasLimitAddStaker = _gasLimitAdd; + emit GasLimitAddStakerUpdated(_oldGasLimitAddStaker, _gasLimitAdd); + } + + /// @notice update gas limit of remove stakers + /// @param _gasLimitRemove cross-chain gas limit remove stakers + function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) external onlyOwner { + require(_gasLimitRemove > 0 && _gasLimitRemove != gasLimitRemoveStakers, "invalid new gas limit"); + uint256 _oldGasLimitRemove = gasLimitRemoveStakers; + gasLimitRemoveStakers = _gasLimitRemove; + emit GasLimitRemoveStakersUpdated(_oldGasLimitRemove, _gasLimitRemove); + } + + /// @notice update challenge deposit + /// @param _challengeDeposit challenge deposit value + function updateChallengeDeposit(uint256 _challengeDeposit) external onlyOwner { + require(_challengeDeposit > 0 && _challengeDeposit != challengeDeposit, "invalid challenge deposit value"); + uint256 _oldChallengeDeposit = challengeDeposit; + challengeDeposit = _challengeDeposit; + emit ChallengeDepositUpdated(_oldChallengeDeposit, _challengeDeposit); + } + + /// @notice update reward percentage + /// @param _rewardPercentage percentage awarded to challenger + function updateRewardPercentage(uint256 _rewardPercentage) external onlyOwner { + require( + _rewardPercentage > 0 && _rewardPercentage <= 100 && _rewardPercentage != rewardPercentage, + "invalid reward percentage" + ); + uint256 _oldRewardPercentage = rewardPercentage; + rewardPercentage = _rewardPercentage; + emit RewardPercentageUpdated(_oldRewardPercentage, _rewardPercentage); + } + + /// @notice clean staker store + function cleanStakerStore() external onlyOwner { + _cleanStakerStore(); + } + + /***************************** + * Public Mutating Functions * + *****************************/ + + /// @notice claim withdrawal + /// @param receiver receiver address + function claimWithdrawal(address receiver) external nonReentrant { + require(withdrawals[_msgSender()] > 0, "withdrawal not exist"); + require(withdrawals[_msgSender()] <= block.number, "withdrawal locked"); + + delete withdrawals[_msgSender()]; + _cleanStakerStore(); + + emit Claimed(_msgSender(), receiver); + + _transfer(receiver, stakingValue); + } + + /************************* + * Public View Functions * + *************************/ + + /// @notice verify BLS signature + function verifySignature( + uint256, // signedSequencersBitmap + address[] calldata, // sequencerSet + bytes32, // msgHash + bytes calldata // signature + ) external pure returns (bool) { + // TODO verify BLS signature + return true; + } + + /// @notice return all stakers + function getStakers() external view returns (address[255] memory) { + return stakerSet; + } + + /// @notice return active stakers + function getActiveStakers() external view returns (address[] memory) { + uint256 activeStakersNumber; + bool[] memory tags = new bool[](255); + for (uint256 i = 0; i < 255; i++) { + // valid address and not in delete list + if (stakerSet[i] != address(0) && deleteableHeight[stakerSet[i]] == 0) { + activeStakersNumber++; + tags[i] = true; + } + } + address[] memory activeStakers = new address[](activeStakersNumber); + uint256 index; + for (uint256 i = 0; i < 255; i++) { + if (tags[i]) { + activeStakers[index] = stakerSet[i]; + index++; + } + } + return activeStakers; + } + + /// @notice whether address is staker + /// @param addr address to check + function isStaker(address addr) public view returns (bool) { + if (stakerIndexes[addr] == 0) { + return false; + } + return stakerSet[stakerIndexes[addr] - 1] == addr; + } + + /// @notice whether address is active staker + /// @param addr address to check + function isActiveStaker(address addr) public view returns (bool) { + if (stakerIndexes[addr] == 0) { + return false; + } + return (stakerSet[stakerIndexes[addr] - 1] == addr) && (deleteableHeight[addr] == 0); + } + + /// @notice whether address in delete list + /// @param addr address to check + function isStakerInDeleteList(address addr) public view returns (bool) { + return deleteableHeight[addr] > 0; + } + + /// @notice get staker bitmap + /// @param _staker the staker address + function getStakerBitmap(address _staker) external view returns (uint256 bitmap) { + require(isStaker(_staker), "invalid staker"); + bitmap = 1 << stakerIndexes[_staker]; + return bitmap; + } + + /// @notice get stakers bitmap + /// @param _stakers the staker address array + function getStakersBitmap(address[] calldata _stakers) external view returns (uint256 bitmap) { + require(_stakers.length <= 255, "stakers length out of bounds"); + for (uint256 i = 0; i < _stakers.length; i++) { + require(isStaker(_stakers[i]), "invalid staker"); + bitmap = bitmap | (1 << stakerIndexes[_stakers[i]]); + } + return bitmap; + } + + /// @notice get stakers from bitmap + /// @param bitmap the stakers bitmap + function getStakersFromBitmap(uint256 bitmap) public view returns (address[] memory stakerAddrs) { + // skip first bit + uint256 _bitmap = bitmap >> 1; + uint256 stakersLength = 0; + while (_bitmap > 0) { + stakersLength = stakersLength + 1; + _bitmap = _bitmap & (_bitmap - 1); + } + + stakerAddrs = new address[](stakersLength); + uint256 index = 0; + for (uint8 i = 1; i <= 255; i++) { + if ((bitmap & (1 << i)) > 0) { + stakerAddrs[index] = stakerSet[i - 1]; + index = index + 1; + if (index >= stakersLength) { + break; + } + } + } + } + + /********************** + * Internal Functions * + **********************/ + + /// @notice add stater + /// @param addr staker address + function _addStaker(address addr) internal { + for (uint8 i = 0; i < 255; i++) { + if (stakerSet[i] == address(0)) { + stakerSet[i] = addr; + stakerIndexes[addr] = i + 1; + return; + } + } + require(false, "slot full"); + } + + /// @notice Add staker to deleteList, it will not be actually deleted until cleanStakerStore is executed + /// @param addr staker address + function _removeStaker(address addr) internal { + require(deleteableHeight[addr] == 0, "already in deleteList"); + deleteList.push(addr); + deleteableHeight[addr] = block.number + withdrawalLockBlocks; + } + + /// @notice transfer ETH + /// @param _to The address to transfer ETH to. + /// @param _amount The amount of ETH to transfer. + function _transfer(address _to, uint256 _amount) internal { + if (_amount > 0) { + (bool success, ) = _to.call{value: _amount}(""); + require(success, "Rollup: ETH transfer failed"); + } + } + + /// @notice add staker + /// @param add staker to add + function _msgAddStaker(Types.StakerInfo memory add) internal { + MESSENGER.sendMessage( + address(OTHER_STAKING), + 0, + abi.encodeCall(IL2Staking.addStaker, (add)), + gasLimitAddStaker + ); + } + + /// @notice remove stakers + /// @param remove stakers to remove + function _msgRemoveStakers(address[] memory remove) internal { + MESSENGER.sendMessage( + address(OTHER_STAKING), + 0, + abi.encodeCall(IL2Staking.removeStakers, (remove)), + gasLimitRemoveStakers + ); + } + + /// @notice clean staker store + function _cleanStakerStore() internal { + uint256 i = 0; + while (i < deleteList.length) { + if (deleteableHeight[deleteList[i]] <= block.number) { + // clean stakerSet + delete stakerSet[stakerIndexes[deleteList[i]] - 1]; + delete stakerIndexes[deleteList[i]]; + + // clean staker info + delete stakers[deleteList[i]]; + + // clean deleteList + delete deleteableHeight[deleteList[i]]; + deleteList[i] = deleteList[deleteList.length - 1]; + deleteList.pop(); + } else { + i++; + } + } + } +} diff --git a/contracts/contracts/test/L1Staking.t.sol b/contracts/contracts/test/L1Staking.t.sol new file mode 100644 index 000000000..825e5040f --- /dev/null +++ b/contracts/contracts/test/L1Staking.t.sol @@ -0,0 +1,1154 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {Predeploys} from "../libraries/constants/Predeploys.sol"; +import {Types} from "../libraries/common/Types.sol"; +import {IL1Staking} from "../l1/staking/IL1Staking.sol"; +import {L1Staking} from "../l1/staking/L1Staking.sol"; +import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; + +// import "forge-std/console.sol"; + +contract StakingInitializeTest is L1MessageBaseTest { + function test_initialize_initializeAgain_revert() external { + // verify the initialize only can be called once. + hevm.expectRevert("Initializable: contract is already initialized"); + l1Staking.initialize( + address(1), + STAKING_VALUE, + CHALLENGE_DEPOSIT, + LOCK_BLOCKS, + rewardPercentage, + defaultGasLimitAdd, + defaultGasLimitRemove + ); + } + + function test_initialize_rollupZeroAddress_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid rollup contract. + hevm.expectRevert("invalid rollup contract"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + ( + address(0), + STAKING_VALUE, + CHALLENGE_DEPOSIT, + LOCK_BLOCKS, + rewardPercentage, + defaultGasLimitAdd, + defaultGasLimitRemove + ) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_stakingValueEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid staking value. + hevm.expectRevert("invalid staking value"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + ( + address(1), + 0, + CHALLENGE_DEPOSIT, + LOCK_BLOCKS, + rewardPercentage, + defaultGasLimitAdd, + defaultGasLimitRemove + ) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_challengeDepositEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid staking value. + hevm.expectRevert("invalid challenge deposit value"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + (address(1), STAKING_VALUE, 0, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, defaultGasLimitRemove) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_lockBlocksEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid withdrawal lock blocks. + hevm.expectRevert("invalid withdrawal lock blocks"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + ( + address(1), + STAKING_VALUE, + CHALLENGE_DEPOSIT, + 0, + rewardPercentage, + defaultGasLimitAdd, + defaultGasLimitRemove + ) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_gasLimitAddEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid gas limit add staker. + hevm.expectRevert("invalid gas limit add staker"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, 0, defaultGasLimitRemove) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_gasLimitRemoveEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid gas limit remove stakers. + hevm.expectRevert("invalid gas limit remove stakers"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, 0) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_rewardPercentageEqZero_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid challenger reward percentage. + hevm.expectRevert("invalid challenger reward percentage"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + ( + address(1), + STAKING_VALUE, + CHALLENGE_DEPOSIT, + LOCK_BLOCKS, + 0, + defaultGasLimitAdd, + defaultGasLimitRemove + ) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_rewardPercentageEq101_revert() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Expect revert due to invalid challenger reward percentage. + hevm.expectRevert("invalid challenger reward percentage"); + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + ( + address(1), + STAKING_VALUE, + CHALLENGE_DEPOSIT, + LOCK_BLOCKS, + 101, + defaultGasLimitAdd, + defaultGasLimitRemove + ) + ) + ); + hevm.stopPrank(); + } + + function test_initialize_succeeds() external { + hevm.startPrank(multisig); + + // Deploy a proxy contract for l1StakingProxyTemp. + TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( + address(emptyContract), + address(multisig), + new bytes(0) + ); + + // Verify the GasLimitAddStakerUpdated event is emitted successful. + hevm.expectEmit(false, false, false, true); + emit IL1Staking.GasLimitAddStakerUpdated(0, 22); + + // Verify the GasLimitRemoveStakersUpdated event is emitted successful. + hevm.expectEmit(false, false, false, true); + emit IL1Staking.GasLimitRemoveStakersUpdated(0, 33); + + // Verify the RewardPercentageUpdated event is emitted successful. + hevm.expectEmit(false, false, false, true); + emit IL1Staking.RewardPercentageUpdated(0, 11); + + ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( + address(l1StakingImpl), + abi.encodeCall( + L1Staking.initialize, + (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, 11, 22, 33) + ) + ); + hevm.stopPrank(); + } +} + +contract StakingTest is L1MessageBaseTest { + function test_setUpCheck_succeeds() external { + assertEq(rollup.l1StakingContract(), address(l1Staking)); + assertEq(address(l1Staking.OTHER_STAKING()), address(Predeploys.L2_STAKING)); + assertEq(address(l1Staking.MESSENGER()), address(l1CrossDomainMessenger)); + assertEq(l1Staking.rollupContract(), address(rollup)); + assertEq(l1Staking.stakingValue(), STAKING_VALUE); + assertEq(l1Staking.withdrawalLockBlocks(), LOCK_BLOCKS); + assertEq(l1Staking.rewardPercentage(), rewardPercentage); + assertEq(l1Staking.gasLimitAddStaker(), 1000000); + assertEq(l1Staking.gasLimitRemoveStakers(), 10000000); + } + + function test_invalidStaker_reverts() external { + // make param + address[] memory sequencers = new address[](2); + sequencers[0] = alice; + sequencers[1] = bob; + hevm.startPrank(address(emptyContract)); + hevm.expectRevert("invalid staker"); + l1Staking.getStakersBitmap(sequencers); + hevm.stopPrank(); + } + + function test_registerAlice_succeeds() external { + hevm.deal(alice, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + hevm.stopPrank(); + hevm.startPrank(alice); + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); + assertEq(addrCheck, alice); + assertEq(tmKeyCheck, stakerInfo.tmKey); + assertBytesEq(blsKeyCheck, stakerInfo.blsKey); + assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); + assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); + hevm.stopPrank(); + } + + function test_stakerWithdrawAndClaim_succeeds() external { + // register + + hevm.deal(bob, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(bob); + address[] memory add = new address[](1); + add[0] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + hevm.stopPrank(); + hevm.startPrank(bob); + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Registered(bob, stakerInfo.tmKey, stakerInfo.blsKey); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(bob); + assertEq(addrCheck, bob); + assertEq(tmKeyCheck, stakerInfo.tmKey); + assertBytesEq(blsKeyCheck, stakerInfo.blsKey); + assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); + assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); + hevm.stopPrank(); + + // withdraw + + hevm.prank(bob); + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Withdrawn(bob, block.number + LOCK_BLOCKS); + l1Staking.withdraw(); + assertFalse(l1Staking.whitelist(bob)); + assertTrue(l1Staking.isStaker(bob)); + assertTrue(l1Staking.isStakerInDeleteList(bob)); + assertTrue(l1Staking.removedList(bob)); + assertEq(l1Staking.withdrawals(bob), block.number + LOCK_BLOCKS); + hevm.stopPrank(); + + // claim + + hevm.prank(bob); + assertEq(bob.balance, 4 * STAKING_VALUE); + hevm.roll(block.number + LOCK_BLOCKS + 1); + l1Staking.claimWithdrawal(bob); + assertEq(bob.balance, 5 * STAKING_VALUE); + assertEq(l1Staking.withdrawals(bob), 0); + hevm.stopPrank(); + } + + function test_stakersBitmap_succeeds() external { + address[] memory stakersAddr = new address[](255); + for (uint256 i = 0; i < 255; i++) { + stakersAddr[i] = address(bytes20(bytes32(keccak256(abi.encodePacked(1500 + i))))); + hevm.deal(stakersAddr[i], 5 * STAKING_VALUE); + } + hevm.prank(multisig); + l1Staking.updateWhitelist(stakersAddr, new address[](0)); + + for (uint256 i = 0; i < 255; i++) { + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(stakersAddr[i]); + hevm.startPrank(stakersAddr[i]); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + hevm.stopPrank(); + } + + uint256 bitmap = l1Staking.getStakersBitmap(stakersAddr); + address[] memory stakersConvert = l1Staking.getStakersFromBitmap(bitmap); + assertEq(stakersAddr.length, stakersConvert.length); + assertEq(stakersAddr[0], stakersConvert[0]); + assertEq(stakersAddr[stakersAddr.length - 1], stakersConvert[stakersConvert.length - 1]); + + // console.logString("......................"); + // console.logUint(bitmap); + // console.logUint(stakersAddr.length); + // console.logUint(stakersConvert.length); + // console.logString("......................"); + } + + function test_slash_succeeds() external { + // TODO + } + + function test_updateParams_succeeds() external { + // TODO + } +} + +contract StakingWhitelistTest is L1MessageBaseTest { + function test_whitelist_notOwner_reverts() external { + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + l1Staking.updateWhitelist(add, new address[](0)); + } + + function test_whitelist_add_succeeds() external { + // make add param + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + + // Verify the WhitelistUpdated event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.WhitelistUpdated(add, new address[](0)); + + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + } + + function test_whitelist_remove_succeeds() external { + address[] memory add = new address[](1); + add[0] = alice; + address[] memory remove = new address[](1); + remove[0] = bob; + + // Verify the WhitelistUpdated event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.WhitelistUpdated(add, remove); + + hevm.prank(multisig); + l1Staking.updateWhitelist(add, remove); + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + } + + function test_whitelist_withdraw_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + hevm.stopPrank(); + + // check + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + } + + function test_whitelist_reAdd_inRemovedList_reverts() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + hevm.stopPrank(); + + // check + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + + hevm.startPrank(multisig); + address[] memory reAdd = new address[](1); + reAdd[0] = bob; + hevm.expectRevert("in removed list"); + l1Staking.updateWhitelist(reAdd, new address[](0)); + hevm.stopPrank(); + } + + function test_whitelist_slash_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + hevm.stopPrank(); + + // bob sequencer to slash + uint256 bitmap = l1Staking.getStakerBitmap(bob); + assertEq(bitmap, 4); + address[] memory stakers = l1Staking.getStakersFromBitmap(bitmap); + assertEq(stakers.length, 1); + assertEq(stakers[0], bob); + hevm.prank(l1Staking.rollupContract()); + l1Staking.slash(bitmap); + + // check + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + } +} + +contract StakingRegisterTest is L1MessageBaseTest { + function test_register_notInWhitelist_reverts() external { + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.startPrank(alice); + hevm.expectRevert("not in whitelist"); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + hevm.stopPrank(); + } + + function test_register_alreadyRegistered_reverts() external { + // add to whitelist + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.startPrank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + hevm.expectRevert("already registered"); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + hevm.stopPrank(); + } + + function test_register_notStakingValue_reverts() external { + // add to whitelist + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.startPrank(alice); + hevm.expectRevert("invalid staking value"); + l1Staking.register{value: STAKING_VALUE - 1}(aliceInfo.tmKey, aliceInfo.blsKey); + hevm.stopPrank(); + } + + function test_register_notTmKey_reverts() external { + // add to whitelist + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.startPrank(alice); + hevm.expectRevert("invalid tendermint pubkey"); + l1Staking.register{value: STAKING_VALUE}(0, aliceInfo.blsKey); + hevm.stopPrank(); + } + + function test_register_notBlsKey_reverts() external { + // add to whitelist + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.startPrank(alice); + hevm.expectRevert("invalid bls pubkey"); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, ""); + hevm.stopPrank(); + } + + function test_register_succeeds() external { + // add to whitelist + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + + (address addressCheck, , ) = l1Staking.stakers(alice); + assertEq(addressCheck, address(0)); + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + assertFalse(l1Staking.blsKeys(aliceInfo.blsKey)); + assertFalse(l1Staking.tmKeys(aliceInfo.tmKey)); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); + assertEq(addrCheck, alice); + assertEq(tmKeyCheck, aliceInfo.tmKey); + assertBytesEq(blsKeyCheck, aliceInfo.blsKey); + assertTrue(l1Staking.blsKeys(aliceInfo.blsKey)); + assertTrue(l1Staking.tmKeys(aliceInfo.tmKey)); + } +} + +contract StakingWithdrawTest is L1MessageBaseTest { + function test_withdraw_notStaker_reverts() external { + // bob withdraw + hevm.expectRevert("only active staker"); + hevm.startPrank(bob); + l1Staking.withdraw(); + hevm.stopPrank(); + } + + function test_withdraw_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // before withdraw + assertEq(l1Staking.withdrawals(bob), 0); + assertTrue(l1Staking.isStaker(bob)); + assertFalse(l1Staking.removedList(bob)); + + // Verify the StakersRemoved event is emitted successfully. + address[] memory remove = new address[](1); + remove[0] = bob; + hevm.expectEmit(true, true, true, true); + emit IL1Staking.StakersRemoved(remove); + + // bob withdraw + l1Staking.withdraw(); + hevm.stopPrank(); + + // after withdraw + // check + assertEq(l1Staking.withdrawals(bob), block.number + l1Staking.withdrawalLockBlocks()); + assertTrue(l1Staking.isStaker(bob)); + assertTrue(l1Staking.isStakerInDeleteList(bob)); + + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + } +} + +contract StakingRemoveStakerTest is L1MessageBaseTest { + // TODO +} + +contract StakingSlashTest is L1MessageBaseTest { + function test_slash_notRollup_reverts() external { + hevm.startPrank(address(emptyContract)); + hevm.expectRevert("only rollup contract"); + l1Staking.slash(0); + hevm.stopPrank(); + } + + function test_slash_withdraw_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + hevm.stopPrank(); + + // bob sequencer to slash + uint256 bitmap = l1Staking.getStakerBitmap(bob); + hevm.prank(l1Staking.rollupContract()); + uint256 reward = l1Staking.slash(bitmap); + assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); + + // check + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + } + + function test_slash_notWithdraw_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + hevm.stopPrank(); + + // bob sequencer to slash + uint256 bitmap = l1Staking.getStakerBitmap(bob); + hevm.prank(l1Staking.rollupContract()); + uint256 reward = l1Staking.slash(bitmap); + assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); + + // check + assertTrue(l1Staking.whitelist(alice)); + assertFalse(l1Staking.whitelist(bob)); + assertFalse(l1Staking.removedList(alice)); + assertTrue(l1Staking.removedList(bob)); + } + + function test_slash_all_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + hevm.stopPrank(); + + address[] memory sequencers = new address[](2); + sequencers[0] = alice; + sequencers[1] = bob; + uint256 beforeBalance = l1Staking.rollupContract().balance; + + // Verify the Slashed event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Slashed(sequencers); + + // Verify the StakersRemoved event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.StakersRemoved(sequencers); + + // sequencer to slash + uint256 bitmap = l1Staking.getStakersBitmap(sequencers); + hevm.prank(l1Staking.rollupContract()); + uint256 reward = l1Staking.slash(bitmap); + assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); + uint256 afterBalance = l1Staking.rollupContract().balance; + assertEq(reward, afterBalance - beforeBalance); + } +} + +contract StakingClaimSlashRemainingTest is L1MessageBaseTest { + function test_claimSlashRemaining_notOwner_reverts() external { + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + l1Staking.claimSlashRemaining(bob); + } + + function test_claimSlashRemaining_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + hevm.stopPrank(); + + address[] memory sequencers = new address[](2); + sequencers[0] = alice; + sequencers[1] = bob; + uint256 beforeBalance = l1Staking.rollupContract().balance; + + // sequencer to slash + uint256 bitmap = l1Staking.getStakersBitmap(sequencers); + hevm.prank(l1Staking.rollupContract()); + uint256 reward = l1Staking.slash(bitmap); + assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); + uint256 afterBalance = l1Staking.rollupContract().balance; + assertEq(reward, afterBalance - beforeBalance); + + // Verify the SlashRemainingClaimed event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.SlashRemainingClaimed(multisig, 2 * STAKING_VALUE - reward); + + uint256 beforeBalanceOfM = multisig.balance; + hevm.prank(multisig); + l1Staking.claimSlashRemaining(multisig); + uint256 afterBalanceOfM = multisig.balance; + emit log_uint(STAKING_VALUE * 2); + emit log_uint(afterBalanceOfM - beforeBalanceOfM); + emit log_uint(reward); + uint256 remaining = 2 * STAKING_VALUE - reward; + assertEq(afterBalanceOfM - beforeBalanceOfM, remaining); + } +} + +contract StakingUpdateGasLimitAddStakerTest is L1MessageBaseTest { + function test_updateGasLimitAddStaker_notOwner_reverts() external { + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + l1Staking.updateGasLimitAddStaker(0); + } + + function test_updateGasLimitAddStaker_eqZero_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid new gas limit"); + l1Staking.updateGasLimitAddStaker(0); + // defaultGasLimitAdd + } + + function test_updateGasLimitAddStaker_eqDefaultValue_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid new gas limit"); + l1Staking.updateGasLimitAddStaker(defaultGasLimitAdd); + } + + function test_updateGasLimitAddStaker_succeeds() external { + uint256 newValue = defaultGasLimitAdd / 10; + uint256 oldValue = l1Staking.gasLimitAddStaker(); + + // Verify the GasLimitAddStakerUpdated event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.GasLimitAddStakerUpdated(oldValue, newValue); + + hevm.prank(multisig); + l1Staking.updateGasLimitAddStaker(newValue); + assertEq(l1Staking.gasLimitAddStaker(), newValue); + } +} + +contract StakingUpdateGasLimitRemoveStakersTest is L1MessageBaseTest { + function test_updateGasLimitRemoveStakers_notOwner_reverts() external { + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + l1Staking.updateGasLimitRemoveStakers(0); + } + + function test_updateGasLimitRemoveStakers_eqZero_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid new gas limit"); + l1Staking.updateGasLimitRemoveStakers(0); + } + + function test_updateGasLimitRemoveStakers_eqDefaultValue_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid new gas limit"); + l1Staking.updateGasLimitRemoveStakers(defaultGasLimitRemove); + } + + function test_updateGasLimitRemoveStakers_succeeds() external { + uint256 newValue = defaultGasLimitRemove / 10; + uint256 oldValue = l1Staking.gasLimitRemoveStakers(); + + // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.GasLimitRemoveStakersUpdated(oldValue, newValue); + + hevm.prank(multisig); + l1Staking.updateGasLimitRemoveStakers(newValue); + assertEq(l1Staking.gasLimitRemoveStakers(), newValue); + } +} + +contract StakingUpdateRewardPercentageTest is L1MessageBaseTest { + function test_updateRewardPercentage_notOwner_reverts() external { + hevm.prank(alice); + hevm.expectRevert("Ownable: caller is not the owner"); + l1Staking.updateRewardPercentage(0); + } + + function test_updateRewardPercentage_eqZero_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid reward percentage"); + l1Staking.updateRewardPercentage(0); + } + + function test_updateRewardPercentage_ge100_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid reward percentage"); + l1Staking.updateRewardPercentage(101); + } + + function test_updateRewardPercentage_eqDefaultValue_reverts() external { + hevm.prank(multisig); + hevm.expectRevert("invalid reward percentage"); + l1Staking.updateRewardPercentage(rewardPercentage); + } + + function test_updateRewardPercentage_succeeds() external { + uint256 newValue = 66; + uint256 oldValue = l1Staking.rewardPercentage(); + + // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.RewardPercentageUpdated(oldValue, newValue); + + hevm.prank(multisig); + l1Staking.updateRewardPercentage(newValue); + assertEq(l1Staking.rewardPercentage(), newValue); + } +} + +contract StakingClaimWithdrawalTest is L1MessageBaseTest { + function test_claimWithdrawal_notWithdraw_reverts() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + hevm.expectRevert("withdrawal not exist"); + l1Staking.claimWithdrawal(bob); + hevm.stopPrank(); + } + + function test_claimWithdrawal_locked_reverts() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + hevm.expectRevert("withdrawal locked"); + l1Staking.claimWithdrawal(bob); + hevm.stopPrank(); + } + + function test_claimWithdrawal_eqLockedBlockNumber_reverts() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + + // set block number + hevm.roll(block.number + l1Staking.withdrawalLockBlocks() - 1); + hevm.expectRevert("withdrawal locked"); + l1Staking.claimWithdrawal(bob); + hevm.stopPrank(); + } + + function test_claimWithdrawal_succeeds() external { + // add to whitelist + address[] memory add = new address[](2); + add[0] = alice; + add[1] = bob; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + assertTrue(l1Staking.whitelist(alice)); + assertTrue(l1Staking.whitelist(bob)); + + // alice register + Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); + hevm.deal(alice, 5 * STAKING_VALUE); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); + + // bob register + Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); + hevm.deal(bob, 5 * STAKING_VALUE); + hevm.startPrank(bob); + l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); + + // bob withdraw + l1Staking.withdraw(); + + // Verify the Claimed event is emitted successfully. + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Claimed(bob, bob); + + // set block number + hevm.roll(block.number + l1Staking.withdrawalLockBlocks() + 1); + uint256 beforeBalance = bob.balance; + l1Staking.claimWithdrawal(bob); + uint256 afterBalance = bob.balance; + assertEq(afterBalance - beforeBalance, STAKING_VALUE); + hevm.stopPrank(); + } +} + +contract StakingVerifySignatureTest is L1MessageBaseTest { + // function testVerifySignature() external { + // l1Staking.verifySignature(); + // } +} diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index acc05e63e..dbcc95c1c 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -2,71 +2,12 @@ pragma solidity =0.8.24; import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; +import {Types} from "../libraries/common/Types.sol"; import {IRollup} from "../l1/rollup/IRollup.sol"; -import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; +import {IL1Staking} from "../l1/staking/IL1Staking.sol"; import {BatchHeaderCodecV0} from "../libraries/codec/BatchHeaderCodecV0.sol"; import {BatchHeaderCodecV1} from "../libraries/codec/BatchHeaderCodecV1.sol"; -contract SubmitterCandidateMock { - enum ReturnMode { - Normal, - RevertCall, - Short, - Long, - BadAddressEncoding - } - - address public declaredRollup; - uint256 public deposit; - uint256 public zeroAddressActive; - ReturnMode public returnMode; - - constructor(address rollup_, uint256 deposit_, uint256 zeroAddressActive_) { - declaredRollup = rollup_; - deposit = deposit_; - zeroAddressActive = zeroAddressActive_; - } - - function setReturnMode(ReturnMode mode) external { - returnMode = mode; - } - - fallback() external { - ReturnMode mode = returnMode; - if (mode == ReturnMode.RevertCall) revert("candidate reverted"); - - uint256 value; - if (msg.sig == ISubmitter.rollupContract.selector) { - value = uint160(declaredRollup); - if (mode == ReturnMode.BadAddressEncoding) value |= uint256(1) << 200; - } else if (msg.sig == ISubmitter.isActive.selector) { - value = zeroAddressActive; - } else if (msg.sig == ISubmitter.challengeDeposit.selector) { - value = deposit; - } else { - revert("unknown selector"); - } - - assembly { - mstore(0, value) - } - if (mode == ReturnMode.Short) { - assembly { - return(0, 31) - } - } - if (mode == ReturnMode.Long) { - assembly { - mstore(32, 1) - return(0, 64) - } - } - assembly { - return(0, 32) - } - } -} - contract RollupCommitBatchWithProofTest is L1MessageBaseTest { /// @dev Test contract for commitBatchWithProof function /// This function allows permissionless batch submission when sequencers are stalled. @@ -74,11 +15,17 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { bytes public batchHeader0; bytes32 public batchHash0; + IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); // Setup batch signature input + batchSignatureInput = IRollup.BatchSignatureInput( + uint256(0), + abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), + bytes("0x") + ); // Import genesis batch bytes memory _batchHeader0 = new bytes(249); @@ -98,15 +45,23 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { rollup.importGenesisBatch(batchHeader0); batchHash0 = rollup.committedBatches(0); - _registerAndStakeSubmitter(alice); + // Setup staker + hevm.deal(alice, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); + address[] memory addrs = new address[](1); + addrs[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(addrs, new address[](0)); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); // Set rollupDelayPeriod (e.g., 1 hour) - no prank needed for hevm.store hevm.store(address(rollup), bytes32(ROLLUP_DELAY_PERIOD_SLOT), bytes32(uint256(3600))); } /// @dev Helper to compute sequencerSetVerifyHash from sequencerSets - function _getSequencerSetVerifyHash() internal pure returns (bytes32) { - return bytes32(0); + function _getSequencerSetVerifyHash() internal view returns (bytes32) { + return keccak256(batchSignatureInput.sequencerSets); } /// @dev Helper to create batch header that matches what _commitBatchWithBatchData produces @@ -187,6 +142,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid timing"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -215,6 +171,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid version"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -241,6 +198,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("V2 requires at least 1 blob"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -268,6 +226,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("Pausable: paused"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -295,6 +254,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("previous state root is zero"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -322,6 +282,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("new state root is zero"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -354,6 +315,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect parent batch hash"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -381,6 +343,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect previous state root"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, bytes("") ); @@ -413,6 +376,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -453,6 +417,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -486,6 +451,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, mockProof ); @@ -520,6 +486,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -575,6 +542,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("l1msg delay"); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -607,6 +575,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(bob); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -657,6 +626,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -691,6 +661,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -709,10 +680,16 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { contract RollupCommitBatchTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); IRollup.BatchDataInput public batchDataInput; + IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); + batchSignatureInput = IRollup.BatchSignatureInput( + uint256(0), + abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), + bytes("0x") + ); } function test_commitAndFinalizeWithL1Messages_succeeds() public { @@ -779,17 +756,27 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 153)), bytesData3) // withdrawRootHash mstore( add(batchHeader1, add(0x20, 185)), - 0 + 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 ) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash } uint64 lastBlockNumber = 1; uint16 numL1Messages = 1; + hevm.mockCall( + address(rollup.l1StakingContract()), + abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), + abi.encode(true) + ); + hevm.mockCall( + address(rollup.l1StakingContract()), + abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), + abi.encode(2) + ); _setupDelayAndWarpForProof(); _mockVerifierForProof(); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(1, keccak256(batchHeader1)); + emit IRollup.CommitBatch(1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); batchDataInput = IRollup.BatchDataInput( 0, batchHeader0, @@ -799,12 +786,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData3 ); - rollup.commitBatchWithProof(batchDataInput, batchHeader1, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader1, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(1)); bytes32 batchHash1 = rollup.committedBatches(1); - assertEq(batchHash1, keccak256(batchHeader1)); + assertEq(batchHash1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); bytes32 stateRoot1 = rollup.committedStateRoots(1); assertEq(stateRoot1, bytesData1); @@ -841,15 +828,26 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader2, add(0x20, 153)), bytesData4) // withdrawRootHash mstore( add(batchHeader2, add(0x20, 185)), - 0 + 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 ) // sequencerSetVerifyHash mstore(add(batchHeader2, add(0x20, 217)), batchHash1) // parentBatchHash mstore(add(batchHeader2, add(0x20, 249)), shl(192, lastBlockNumber)) // lastBlockNumber } + hevm.prank(multisig); + hevm.mockCall( + address(rollup.l1StakingContract()), + abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), + abi.encode(true) + ); + hevm.mockCall( + address(rollup.l1StakingContract()), + abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), + abi.encode(2) + ); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(2, keccak256(batchHeader2)); + emit IRollup.CommitBatch(2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); batchDataInput = IRollup.BatchDataInput( 1, @@ -860,12 +858,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData4 ); - rollup.commitBatchWithProof(batchDataInput, batchHeader2, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader2, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(2)); bytes32 batchHash2 = rollup.committedBatches(2); - assertEq(batchHash2, keccak256(batchHeader2)); + assertEq(batchHash2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); bytes32 stateRoot2 = rollup.committedStateRoots(2); assertEq(stateRoot2, bytesData1); @@ -891,11 +889,36 @@ contract RollupTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; + IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); + batchSignatureInput = IRollup.BatchSignatureInput( + uint256(0), + abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), + bytes("0x") + ); - _registerAndStakeSubmitter(alice); + // add staker + + hevm.deal(alice, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + hevm.stopPrank(); + hevm.startPrank(alice); + hevm.expectEmit(true, true, true, true); + emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); + assertEq(addrCheck, alice); + assertEq(tmKeyCheck, stakerInfo.tmKey); + assertBytesEq(blsKeyCheck, stakerInfo.blsKey); + assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); + assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); + hevm.stopPrank(); } function test_commitBatches_succeeds() external { @@ -917,19 +940,66 @@ contract RollupTest is L1MessageBaseTest { } hevm.prank(multisig); rollup.importGenesisBatch(batchHeader0); - // only active submitter allowed, revert + // only active staker allowed, revert hevm.startPrank(address(0)); - hevm.expectRevert("only active submitter allowed"); + hevm.expectRevert("only active staker allowed"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput); + rollup.commitBatch(batchDataInput, batchSignatureInput); hevm.stopPrank(); - // The official path is structurally fresh-blob only. This Foundry version cannot - // attach a blob sidecar, so validation after the blob gate is covered by withProof. + // invalid version, revert (version 3+ is invalid; version 2 is now valid V2 multi-blob) hevm.startPrank(alice); - hevm.expectRevert("must carry blob"); + hevm.expectRevert("invalid version"); + batchDataInput = IRollup.BatchDataInput(3, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); + rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.stopPrank(); + + // batch header length incorrect, revert + hevm.startPrank(alice); + hevm.expectRevert("batch header length too small"); + batchDataInput = IRollup.BatchDataInput(0, new bytes(120), 0, 0, stateRoot, stateRoot, getTreeRoot()); + rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.stopPrank(); + + // incorrect batch index, revert + assembly { + mstore(add(batchHeader0, add(0x20, 1)), shl(192, 1)) // change batch index to 1 + } + hevm.startPrank(alice); + hevm.expectRevert("incorrect batch index"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput); + rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.stopPrank(); + assembly { + mstore(add(batchHeader0, add(0x20, 1)), 0) // change back + } + + // incorrect parent batch hash, revert + assembly { + mstore(add(batchHeader0, add(0x20, 25)), 2) // change data hash for batch0 + } + hevm.startPrank(alice); + hevm.expectRevert("incorrect parent batch hash"); + batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); + rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.stopPrank(); + assembly { + mstore(add(batchHeader0, add(0x20, 25)), 1) // change back + mstore(add(batchHeader0, add(0x20, 57)), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) + } + + // incorrect previous state root, revert + hevm.startPrank(alice); + hevm.expectRevert("incorrect previous state root"); + batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, bytes32(uint256(2)), stateRoot, getTreeRoot()); + rollup.commitBatch(batchDataInput, batchSignatureInput); + hevm.stopPrank(); + + // incorrect batch header length, revert + hevm.startPrank(alice); + hevm.expectRevert("batch header length too small"); + batchDataInput = IRollup.BatchDataInput(0, new bytes(248), 0, 0, stateRoot, stateRoot, getTreeRoot()); + rollup.commitBatch(batchDataInput, batchSignatureInput); hevm.stopPrank(); // commit batch with one chunk, no tx, correctly (commitBatch requires blob when no stored hash; use commitBatchWithProof) @@ -944,7 +1014,7 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, getTreeRoot(), - bytes32(0), + keccak256(batchSignatureInput.sequencerSets), rollup.committedBatches(0) ); hevm.startPrank(alice); @@ -952,17 +1022,18 @@ contract RollupTest is L1MessageBaseTest { hevm.deal(address(0), 10 ether); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); hevm.stopPrank(); assertGt(uint256(rollup.committedBatches(1)), 0); - // The fresh-blob gate remains first even if the target index is already occupied. + // batch is already committed, revert (commitBatch also reverts with "commitBatch requires no stored blob hash" when slot is set) hevm.startPrank(alice); - hevm.expectRevert("must carry blob"); + hevm.expectRevert("commitBatch requires no stored blob hash"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput); + rollup.commitBatch(batchDataInput, batchSignatureInput); hevm.stopPrank(); } @@ -1000,18 +1071,19 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - bytes32(0), + keccak256(batchSignatureInput.sequencerSets), batchHash0 ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); hevm.stopPrank(); - assertEq(rollup.committedBatches(1), keccak256(batchHeader1ForProof)); + assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); // warp again so second commitBatchWithProof passes rollupDelay (batchDataStore[1].originTimestamp + period < block.timestamp) hevm.warp(block.timestamp + 3601); bytes memory batchHeader1 = new bytes(249); @@ -1027,7 +1099,7 @@ contract RollupTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 153)), bytesData4) // withdrawRootHash mstore( add(batchHeader1, add(0x20, 185)), - 0 + 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 ) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash mstore(add(batchHeader1, add(0x20, 249)), 0) // bitmap0 @@ -1043,13 +1115,14 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - bytes32(0), + keccak256(batchSignatureInput.sequencerSets), rollup.committedBatches(1) ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader1, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader2ForProof, hex"deadbeef" ); @@ -1107,7 +1180,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("Pausable: paused"); batchDataInput = IRollup.BatchDataInput(0, new bytes(0), 0, 0, stateRoot, stateRoot, bytes32(uint256(4))); - rollup.commitBatch(batchDataInput); + rollup.commitBatch(batchDataInput, batchSignatureInput); hevm.expectRevert("Pausable: paused"); rollup.finalizeBatch(new bytes(0)); @@ -1221,10 +1294,23 @@ contract RollupTest is L1MessageBaseTest { contract RollupCommitStateTest is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; + IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - _registerAndStakeSubmitter(alice); + batchSignatureInput = IRollup.BatchSignatureInput( + uint256(0), + abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), + bytes("0x") + ); + hevm.deal(alice, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); + address[] memory add = new address[](1); + add[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(add, new address[](0)); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); } function _genesisBatchHeader() internal pure returns (bytes memory batchHeader0) { @@ -1248,7 +1334,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - bytes32(0), + keccak256(batchSignatureInput.sequencerSets), parentBatchHash ); } @@ -1267,7 +1353,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), bytesData1) mstore(add(batchHeader1, add(0x20, 121)), bytesData1) mstore(add(batchHeader1, add(0x20, 153)), bytesData4) - mstore(add(batchHeader1, add(0x20, 185)), 0) + mstore(add(batchHeader1, add(0x20, 185)), 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067) mstore(add(batchHeader1, add(0x20, 217)), parentBatchHash) mstore(add(batchHeader1, add(0x20, 249)), 0) } @@ -1287,6 +1373,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); @@ -1310,11 +1397,11 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, + batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); - bytes32 expectedBatchHash = keccak256(batchHeader1ForProof); - assertEq(rollup.committedBatches(1), expectedBatchHash); + assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); assertGt(uint256(rollup.batchBlobVersionedHashes(1)), 0); // Revert batch 1 (blob hash is preserved) @@ -1328,8 +1415,8 @@ contract RollupCommitStateTest is L1MessageBaseTest { // Recommit with commitState (no blob in tx; uses stored blob hash) batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput); - assertEq(rollup.committedBatches(1), expectedBatchHash); + rollup.commitState(batchDataInput, batchSignatureInput); + assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); assertEq(uint256(rollup.lastCommittedBatchIndex()), 1); } @@ -1341,7 +1428,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput); + rollup.commitState(batchDataInput, batchSignatureInput); // Without blob in tx, commitState succeeds. Revert "commitState must not carry blob" is hit only when blobhash(0) != 0 (blob tx). assertEq(rollup.lastCommittedBatchIndex(), 1); } @@ -1355,315 +1442,59 @@ contract RollupCommitStateTest is L1MessageBaseTest { batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); hevm.expectRevert("no stored blob hash for this batch"); - rollup.commitState(batchDataInput); + rollup.commitState(batchDataInput, batchSignatureInput); } /// @dev commitState can only be called by an active staker. - function test_commitState_only_active_submitter() public { + function test_commitState_only_active_staker() public { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(address(1)); - hevm.expectRevert("only active submitter allowed"); - rollup.commitState(batchDataInput); + hevm.expectRevert("only active staker allowed"); + rollup.commitState(batchDataInput, batchSignatureInput); } - /// @dev commitBatch is fresh-blob only even when a stale stored hash exists. - function test_commitBatch_requires_blob_when_stored_hash_exists() public { + /// @dev Mutual exclusion: (1) commitBatch reverts when stored blob hash exists; (2) commitState reverts when no stored hash (see test_commitState_reverts_when_no_stored_blob_hash). + function test_commitState_commitBatch_mutual_exclusion() public { bytes memory batchHeader0 = _genesisBatchHeader(); hevm.prank(multisig); rollup.importGenesisBatch(batchHeader0); - // A real blob transaction may overwrite this stale value; a no-blob call cannot. + // When there IS stored blob hash for batch 1, commitBatch must revert _setStoredBlobHash(1); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - hevm.expectRevert("must carry blob"); - rollup.commitBatch(batchDataInput); + hevm.expectRevert("commitBatch requires no stored blob hash"); + rollup.commitBatch(batchDataInput, batchSignatureInput); } } -contract RollupSubmitterCutoverTest is L1MessageBaseTest { - bytes32 internal constant ROOT_1 = bytes32(uint256(1)); - bytes32 internal constant ROOT_2 = bytes32(uint256(2)); - bytes32 internal constant ROOT_3 = bytes32(uint256(3)); - uint256 internal constant BATCH_DATA_STORE_SLOT = 162; - uint256 internal constant PENDING_BATCH_COUNT_SLOT = 174; - - function setUp() public virtual override { - super.setUp(); - _registerAndStakeSubmitter(alice); - _registerAndStakeSubmitter(bob); - } - - function test_currentSelectorsAreDistinctFromPreSubmitterSelectors() public { - assertEq(IRollup.commitBatch.selector, bytes4(0x41f756da)); - assertEq(IRollup.commitState.selector, bytes4(0x67caa37a)); - assertEq(IRollup.commitBatchWithProof.selector, bytes4(0x1544ba3a)); - assertTrue(IRollup.commitBatch.selector != bytes4(0x428868b5)); - assertTrue(IRollup.commitState.selector != bytes4(0x1e8825be)); - assertTrue(IRollup.commitBatchWithProof.selector != bytes4(0x4e8f1d67)); - } - - function test_liabilityReleasedExactlyByRevertAndFinalize() public { - bytes memory header0 = _importGenesis(); - bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); - bytes memory header2 = _commitStateAs(bob, header1, 2, ROOT_2, ROOT_3); - - assertEq(rollup.pendingBatchCount(alice), 1); - assertEq(rollup.pendingBatchCount(bob), 1); - (, , , address batch1Submitter) = rollup.batchDataStore(1); - (, , , address batch2Submitter) = rollup.batchDataStore(2); - assertEq(batch1Submitter, alice); - assertEq(batch2Submitter, bob); - - hevm.prank(multisig); - rollup.revertBatch(header2, 1); - assertEq(rollup.pendingBatchCount(alice), 1); - assertEq(rollup.pendingBatchCount(bob), 0); - - hevm.warp(block.timestamp + finalizationPeriodSeconds + 1); - rollup.finalizeBatch(header1); - assertEq(rollup.pendingBatchCount(alice), 0); - } - - function test_challengeAndSlashDoNotReleaseLiability() public { - bytes memory header0 = _importGenesis(); - bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); - bytes32 batchHash = rollup.committedBatches(1); - - hevm.prank(bob); - rollup.challengeState{value: CHALLENGE_DEPOSIT}(1, batchHash); - hevm.warp(block.timestamp + proofWindow + 1); - hevm.prank(alice); - rollup.proveState(header1, hex"01"); - - assertEq(rollup.pendingBatchCount(alice), 1); - assertEq(rollup.revertReqIndex(), 1); - assertEq(submitter.stakeOf(alice), 0); - - hevm.prank(multisig); - rollup.revertBatch(header1, 1); - assertEq(rollup.pendingBatchCount(alice), 0); - assertEq(rollup.revertReqIndex(), 0); - } - - function test_permissionlessProofUsesZeroSubmitterAndZeroHeaderField() public { - bytes memory header0 = _importGenesis(); - _setupDelayAndWarpForProof(); - _mockMessageQueueNotDelayedForProof(); - _mockVerifierForProof(); - - bytes memory header1 = _createBatchHeaderV0ForProof( - 1, - 0, - 0, - _computeDataHash(1, 0), - ROOT_1, - ROOT_2, - bytes32(uint256(101)), - bytes32(0), - rollup.committedBatches(0) - ); - IRollup.BatchDataInput memory input = IRollup.BatchDataInput( - 0, - header0, - 1, - 0, - ROOT_1, - ROOT_2, - bytes32(uint256(101)) - ); - - hevm.prank(address(0xBEEF)); - rollup.commitBatchWithProof(input, header1, hex"01"); - - (, , , address liable) = rollup.batchDataStore(1); - assertEq(liable, address(0)); - assertEq(rollup.pendingBatchCount(address(0xBEEF)), 0); - bytes32 sequencerSetVerifyHash; - assembly { - sequencerSetVerifyHash := mload(add(add(header1, 0x20), 185)) - } - assertEq(sequencerSetVerifyHash, bytes32(0)); - assertEq(rollup.committedBatches(1), keccak256(header1)); - } - - function test_liabilityUnderflowFailsClosed() public { - bytes memory header0 = _importGenesis(); - bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); - bytes32 countSlot = keccak256(abi.encode(alice, PENDING_BATCH_COUNT_SLOT)); - hevm.store(address(rollup), countSlot, bytes32(0)); - - hevm.prank(multisig); - hevm.expectRevert("pending batch count underflow"); - rollup.revertBatch(header1, 1); - assertEq(rollup.lastCommittedBatchIndex(), 1); - } - - function test_initialize2And3AreOwnerOnly() public { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - rollup.initialize2(ROOT_1); - hevm.prank(multisig); - rollup.initialize2(ROOT_1); - - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - rollup.initialize3(3600); - hevm.prank(multisig); - rollup.initialize3(3600); - } - - function test_initialize4ValidatesInterfaceAndClearsLegacyTailOwnerField() public { - _importGenesis(); - bytes32 batchDataBase = keccak256(abi.encode(uint256(0), BATCH_DATA_STORE_SLOT)); - hevm.store(address(rollup), bytes32(uint256(batchDataBase) + 3), bytes32(uint256(uint160(alice)))); - (uint256 originBefore, uint256 finalizeBefore, uint256 blockBefore, address legacyTail) = rollup - .batchDataStore(0); - assertEq(legacyTail, alice); - - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - rollup.initialize4(address(submitter)); - - hevm.prank(multisig); - hevm.expectRevert("invalid submitter"); - rollup.initialize4(address(0x1234)); - - SubmitterCandidateMock malformed = new SubmitterCandidateMock(address(rollup), CHALLENGE_DEPOSIT, 0); - malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.Short); - hevm.prank(multisig); - hevm.expectRevert("invalid submitter interface"); - rollup.initialize4(address(malformed)); - malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.Long); - hevm.prank(multisig); - hevm.expectRevert("invalid submitter interface"); - rollup.initialize4(address(malformed)); - malformed.setReturnMode(SubmitterCandidateMock.ReturnMode.BadAddressEncoding); - hevm.prank(multisig); - hevm.expectRevert("invalid rollup encoding"); - rollup.initialize4(address(malformed)); - - SubmitterCandidateMock mismatch = new SubmitterCandidateMock(address(1), CHALLENGE_DEPOSIT, 0); - hevm.prank(multisig); - hevm.expectRevert("submitter rollup mismatch"); - rollup.initialize4(address(mismatch)); - SubmitterCandidateMock badActive = new SubmitterCandidateMock(address(rollup), CHALLENGE_DEPOSIT, 1); - hevm.prank(multisig); - hevm.expectRevert("invalid submitter state"); - rollup.initialize4(address(badActive)); - SubmitterCandidateMock zeroDeposit = new SubmitterCandidateMock(address(rollup), 0, 0); - hevm.prank(multisig); - hevm.expectRevert("invalid submitter state"); - rollup.initialize4(address(zeroDeposit)); - - hevm.prank(multisig); - rollup.initialize4(address(submitter)); - assertEq(rollup.submitterContract(), address(submitter)); - (uint256 originAfter, uint256 finalizeAfter, uint256 blockAfter, address tailSubmitter) = rollup.batchDataStore( - 0 - ); - assertEq(originAfter, originBefore); - assertEq(finalizeAfter, finalizeBefore); - assertEq(blockAfter, blockBefore); - assertEq(tailSubmitter, address(0)); - - hevm.prank(multisig); - hevm.expectRevert("Initializable: contract is already initialized"); - rollup.initialize4(address(submitter)); - } - - function test_initialize4PendingBatchRevertsWithoutConsumingVersion() public { - bytes memory header0 = _importGenesis(); - bytes memory header1 = _commitStateAs(alice, header0, 1, ROOT_1, ROOT_2); - - hevm.prank(multisig); - hevm.expectRevert("pending batches"); - rollup.initialize4(address(submitter)); - - hevm.prank(multisig); - rollup.revertBatch(header1, 1); - hevm.prank(multisig); - rollup.initialize4(address(submitter)); - } - - function _importGenesis() internal returns (bytes memory header0) { - header0 = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); - assembly { - mstore(add(header0, add(0x20, 25)), 1) - mstore(add(header0, add(0x20, 57)), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) - mstore(add(header0, add(0x20, 121)), 1) - } - hevm.prank(multisig); - rollup.importGenesisBatch(header0); - } - - function _commitStateAs( - address actor, - bytes memory parentHeader, - uint256 batchIndex, - bytes32 previousRoot, - bytes32 postRoot - ) internal returns (bytes memory header) { - _setStoredBlobHash(batchIndex); - hevm.mockCall( - address(l1MessageQueueWithGasPriceOracle), - abi.encodeWithSignature("getFirstUnfinalizedMessageEnqueueTime()"), - abi.encode(block.timestamp) - ); - bytes32 withdrawalRoot = bytes32(batchIndex + 100); - IRollup.BatchDataInput memory input = IRollup.BatchDataInput( - 0, - parentHeader, - uint64(batchIndex), - 0, - previousRoot, - postRoot, - withdrawalRoot - ); - hevm.prank(actor); - rollup.commitState(input); - - header = _buildStateHeader(batchIndex, previousRoot, postRoot, withdrawalRoot); - assertEq(rollup.committedBatches(batchIndex), keccak256(header)); - } - - function _buildStateHeader( - uint256 batchIndex, - bytes32 previousRoot, - bytes32 postRoot, - bytes32 withdrawalRoot - ) internal view returns (bytes memory header) { - header = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); - bytes32 dataHash = _computeDataHash(uint64(batchIndex), 0); - bytes32 parentHash = rollup.committedBatches(batchIndex - 1); - assembly { - let p := add(header, 0x20) - mstore(p, 0) - mstore(add(p, 1), shl(192, batchIndex)) - mstore(add(p, 25), dataHash) - mstore(add(p, 57), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) - mstore(add(p, 89), previousRoot) - mstore(add(p, 121), postRoot) - mstore(add(p, 153), withdrawalRoot) - mstore(add(p, 185), 0) - mstore(add(p, 217), parentHash) - } - } -} - /// @dev Tests for Rollup V2 multi-blob batch header support (simplified: 257-byte header with aggregated blob hash). contract RollupCommitBatchV2Test is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); + IRollup.BatchSignatureInput public batchSignatureInput; bytes public batchHeader0; bytes32 public batchHash0; function setUp() public virtual override { super.setUp(); + batchSignatureInput = IRollup.BatchSignatureInput( + uint256(0), + abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), + bytes("0x") + ); - _registerAndStakeSubmitter(alice); + // Register staker + hevm.deal(alice, 5 * STAKING_VALUE); + Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); + address[] memory addrs = new address[](1); + addrs[0] = alice; + hevm.prank(multisig); + l1Staking.updateWhitelist(addrs, new address[](0)); + hevm.prank(alice); + l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); // Import genesis batch (V0) bytes memory _genesis = new bytes(249); @@ -1726,7 +1557,7 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { Rollup Integration Tests //////////////////////////////////////////////////////////////*/ - /// @dev commitBatch with must carry blob (reverts in test env where blobhash(0)=0). + /// @dev commitBatch with V2 requires at least 1 blob (reverts in test env where blobhash(0)=0). function test_commitBatchV2_reverts_without_blob() public { IRollup.BatchDataInput memory batchDataInput = IRollup.BatchDataInput({ version: 2, @@ -1739,8 +1570,8 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { }); hevm.prank(alice); - hevm.expectRevert("must carry blob"); - rollup.commitBatch(batchDataInput); + hevm.expectRevert("V2 requires at least 1 blob"); + rollup.commitBatch(batchDataInput, batchSignatureInput); } /// @dev V2 _loadBatchHeader accepts a valid 257-byte V2 header (uses V1 loader). diff --git a/contracts/contracts/test/Submitter.t.sol b/contracts/contracts/test/Submitter.t.sol deleted file mode 100644 index c8637f63b..000000000 --- a/contracts/contracts/test/Submitter.t.sol +++ /dev/null @@ -1,461 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import "forge-std/Test.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; - -import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; -import {Submitter} from "../l1/rollup/Submitter.sol"; - -contract LiabilityRollupMock { - enum ReturnMode { - Normal, - RevertCall, - Short, - Long, - BurnGas - } - - mapping(address submitter => uint256 count) public counts; - ReturnMode public returnMode; - - function setPendingBatchCount(address submitter, uint256 count) external { - counts[submitter] = count; - } - - function setReturnMode(ReturnMode mode) external { - returnMode = mode; - } - - function slash(ISubmitter submitterContract, address submitter) external returns (uint256) { - return submitterContract.slash(submitter); - } - - receive() external payable {} - - fallback() external payable { - require(msg.sig == bytes4(keccak256("pendingBatchCount(address)")), "unknown selector"); - ReturnMode mode = returnMode; - address submitter; - assembly { - submitter := calldataload(4) - } - uint256 count = counts[submitter]; - if (mode == ReturnMode.RevertCall) revert("getter reverted"); - if (mode == ReturnMode.BurnGas) { - assembly { - for {} 1 {} {} - } - } - assembly { - mstore(0, count) - } - if (mode == ReturnMode.Short) { - assembly { - return(0, 31) - } - } - if (mode == ReturnMode.Long) { - assembly { - mstore(32, 1) - return(0, 64) - } - } - assembly { - return(0, 32) - } - } -} - -contract RejectEther { - function stakeInto(Submitter target) external { - target.stake{value: address(this).balance}(); - } - - function claimFrom(Submitter target, address receiver) external { - target.claimCredit(receiver); - } - - receive() external payable { - revert("reject ether"); - } -} - -contract BurnRefundGas { - receive() external payable { - assembly { - for {} 1 {} {} - } - } -} - -contract ReentrantSubmitterActor { - Submitter internal immutable target; - bool public reentrySucceeded; - bytes32 public reentryErrorHash; - - constructor(Submitter target_) { - target = target_; - } - - function stakeInto() external { - target.stake{value: address(this).balance}(); - } - - function withdrawToSelf() external { - target.withdraw(address(this)); - } - - receive() external payable { - try target.claimWithdrawal(address(this)) { - reentrySucceeded = true; - } catch (bytes memory reason) { - reentryErrorHash = keccak256(reason); - } - } -} - -contract SubmitterTest is Test { - uint256 internal constant MINIMUM_STAKE = 1 ether; - uint256 internal constant CHALLENGE_DEPOSIT = 2 ether; - uint256 internal constant REWARD_PERCENTAGE = 25; - - address internal owner = address(0xA11CE); - address internal proxyAdmin = address(0xA11); - address internal alice = address(0xB0B); - address internal bob = address(0xCAFE); - - LiabilityRollupMock internal rollupMock; - Submitter internal implementation; - Submitter internal submitter; - - function setUp() public { - vm.deal(alice, 100 ether); - vm.deal(bob, 100 ether); - rollupMock = new LiabilityRollupMock(); - implementation = new Submitter(); - TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( - address(implementation), - proxyAdmin, - abi.encodeCall( - Submitter.initialize, (owner, address(rollupMock), MINIMUM_STAKE, CHALLENGE_DEPOSIT, REWARD_PERCENTAGE) - ) - ); - submitter = Submitter(payable(address(proxy))); - } - - function test_initialize_proxyAndImplementationProtection() public { - assertEq(submitter.owner(), owner); - assertEq(submitter.rollupContract(), address(rollupMock)); - assertEq(submitter.minimumStake(), MINIMUM_STAKE); - assertEq(submitter.challengeDeposit(), CHALLENGE_DEPOSIT); - assertEq(submitter.rewardPercentage(), REWARD_PERCENTAGE); - - vm.expectRevert("Initializable: contract is already initialized"); - implementation.initialize(owner, address(rollupMock), 1, 1, 1); - - vm.prank(owner); - vm.expectRevert("Initializable: contract is already initialized"); - submitter.initialize(owner, address(rollupMock), 1, 1, 1); - } - - function test_initialize_rejectsInvalidParameters() public { - _expectProxyInitializationRevert(address(0), address(rollupMock), 1, 1, 1, "invalid owner"); - _expectProxyInitializationRevert(owner, address(0), 1, 1, 1, "invalid rollup contract"); - _expectProxyInitializationRevert(owner, alice, 1, 1, 1, "invalid rollup contract"); - _expectProxyInitializationRevert(owner, address(rollupMock), 0, 1, 1, "invalid minimum stake"); - _expectProxyInitializationRevert(owner, address(rollupMock), 1, 0, 1, "invalid challenge deposit"); - _expectProxyInitializationRevert(owner, address(rollupMock), 1, 1, 0, "invalid reward percentage"); - _expectProxyInitializationRevert(owner, address(rollupMock), 1, 1, 101, "invalid reward percentage"); - } - - function test_addStakeAndDynamicMinimum() public { - vm.prank(alice); - vm.expectRevert("Ownable: caller is not the owner"); - submitter.addSubmitter(alice); - - vm.prank(owner); - submitter.addSubmitter(alice); - assertFalse(submitter.isActive(alice)); - - vm.prank(alice); - vm.expectRevert("below minimum stake"); - submitter.stake{value: MINIMUM_STAKE - 1}(); - - vm.prank(alice); - submitter.stake{value: MINIMUM_STAKE}(); - assertTrue(submitter.isActive(alice)); - - vm.prank(owner); - submitter.setMinimumStake(2 ether); - assertFalse(submitter.isActive(alice)); - - vm.prank(alice); - vm.expectRevert("below minimum stake"); - submitter.stake{value: 0.5 ether}(); - vm.prank(alice); - submitter.stake{value: 1 ether}(); - assertTrue(submitter.isActive(alice)); - - vm.prank(owner); - submitter.setMinimumStake(3 ether); - assertFalse(submitter.isActive(alice)); - vm.prank(owner); - submitter.setMinimumStake(2 ether); - assertTrue(submitter.isActive(alice)); - } - - function test_multipleSubmittersCanBeActive() public { - _registerAndStake(alice, MINIMUM_STAKE); - _registerAndStake(bob, MINIMUM_STAKE + 1); - assertTrue(submitter.isActive(alice)); - assertTrue(submitter.isActive(bob)); - } - - function test_withdraw_noLiabilityPaysAndRequiresFreshRegistration() public { - _registerAndStake(alice, MINIMUM_STAKE); - uint256 before = bob.balance; - - vm.prank(alice); - submitter.withdraw(bob); - - assertEq(bob.balance - before, MINIMUM_STAKE); - assertEq(submitter.stakeOf(alice), 0); - assertFalse(submitter.exiting(alice)); - assertFalse(submitter.registered(alice)); - vm.prank(alice); - vm.expectRevert("not stakeable"); - submitter.stake{value: MINIMUM_STAKE}(); - } - - function test_remove_pendingExitRejectsDuplicateAddUntilClaimed() public { - vm.prank(owner); - submitter.addSubmitter(alice); - vm.prank(owner); - vm.expectRevert("invalid submitter"); - submitter.addSubmitter(alice); - - vm.prank(alice); - submitter.stake{value: MINIMUM_STAKE}(); - rollupMock.setPendingBatchCount(alice, 1); - vm.prank(owner); - submitter.removeSubmitter(alice); - - assertFalse(submitter.registered(alice)); - assertTrue(submitter.exiting(alice)); - assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); - vm.prank(owner); - vm.expectRevert("invalid submitter"); - submitter.addSubmitter(alice); - vm.prank(alice); - vm.expectRevert("pending batch liability"); - submitter.claimWithdrawal(alice); - - rollupMock.setPendingBatchCount(alice, 0); - vm.prank(alice); - submitter.claimWithdrawal(alice); - vm.prank(owner); - submitter.addSubmitter(alice); - assertTrue(submitter.registered(alice)); - } - - function test_exit_keepsStakeSlashable_untilAllBatchesTerminate() public { - _registerAndStake(alice, MINIMUM_STAKE); - rollupMock.setPendingBatchCount(alice, 2); - - vm.prank(alice); - submitter.withdraw(alice); - assertFalse(submitter.isActive(alice)); - assertTrue(submitter.exiting(alice)); - assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); - - uint256 reward = rollupMock.slash(submitter, alice); - assertEq(reward, MINIMUM_STAKE / 4); - assertEq(submitter.stakeOf(alice), 0); - assertTrue(submitter.exiting(alice)); - assertFalse(submitter.registered(alice)); - - rollupMock.setPendingBatchCount(alice, 0); - vm.prank(alice); - submitter.claimWithdrawal(alice); - assertFalse(submitter.exiting(alice)); - vm.prank(alice); - vm.expectRevert("not stakeable"); - submitter.stake{value: MINIMUM_STAKE}(); - - vm.prank(owner); - submitter.addSubmitter(alice); - vm.prank(alice); - submitter.stake{value: MINIMUM_STAKE}(); - assertTrue(submitter.isActive(alice)); - } - - function test_withdraw_getterFailuresFailClosed() public { - LiabilityRollupMock.ReturnMode[4] memory modes = [ - LiabilityRollupMock.ReturnMode.RevertCall, - LiabilityRollupMock.ReturnMode.Short, - LiabilityRollupMock.ReturnMode.Long, - LiabilityRollupMock.ReturnMode.BurnGas - ]; - for (uint256 i; i < modes.length; ++i) { - address actor = address(uint160(0x1000 + i)); - vm.deal(actor, 10 ether); - _registerAndStake(actor, MINIMUM_STAKE); - rollupMock.setReturnMode(modes[i]); - vm.prank(actor); - submitter.withdraw(actor); - assertFalse(submitter.isActive(actor)); - assertTrue(submitter.exiting(actor)); - assertEq(submitter.stakeOf(actor), MINIMUM_STAKE); - rollupMock.setReturnMode(LiabilityRollupMock.ReturnMode.Normal); - vm.prank(actor); - submitter.claimWithdrawal(actor); - } - } - - function test_receiverFailureCreditsWithoutBlockingRemove() public { - RejectEther actor = new RejectEther(); - vm.deal(address(actor), MINIMUM_STAKE); - vm.prank(owner); - submitter.addSubmitter(address(actor)); - actor.stakeInto(submitter); - - vm.prank(owner); - submitter.removeSubmitter(address(actor)); - assertFalse(submitter.registered(address(actor))); - assertFalse(submitter.exiting(address(actor))); - assertEq(submitter.claimable(address(actor)), MINIMUM_STAKE); - - uint256 before = bob.balance; - actor.claimFrom(submitter, bob); - assertEq(bob.balance - before, MINIMUM_STAKE); - assertEq(submitter.claimable(address(actor)), 0); - } - - function test_withdraw_revertingAndGasBurningReceiversBecomeCredit() public { - RejectEther reject = new RejectEther(); - BurnRefundGas burner = new BurnRefundGas(); - - _registerAndStake(alice, MINIMUM_STAKE); - vm.prank(alice); - submitter.withdraw(address(reject)); - assertEq(submitter.claimable(alice), MINIMUM_STAKE); - - _registerAndStake(bob, MINIMUM_STAKE); - vm.prank(bob); - submitter.withdraw(address(burner)); - assertEq(submitter.claimable(bob), MINIMUM_STAKE); - } - - function test_withdraw_receiverReentryIsBlocked() public { - ReentrantSubmitterActor actor = new ReentrantSubmitterActor(submitter); - vm.deal(address(actor), MINIMUM_STAKE); - vm.prank(owner); - submitter.addSubmitter(address(actor)); - actor.stakeInto(); - - actor.withdrawToSelf(); - - assertFalse(actor.reentrySucceeded()); - assertEq( - actor.reentryErrorHash(), - keccak256(abi.encodeWithSignature("Error(string)", "ReentrancyGuard: reentrant call")) - ); - assertEq(address(actor).balance, MINIMUM_STAKE); - assertEq(submitter.stakeOf(address(actor)), 0); - } - - function test_claimCreditFailureRollsBackCredit() public { - RejectEther reject = new RejectEther(); - _registerAndStake(alice, MINIMUM_STAKE); - vm.prank(alice); - submitter.withdraw(address(reject)); - - vm.prank(alice); - vm.expectRevert("ETH transfer failed"); - submitter.claimCredit(address(reject)); - assertEq(submitter.claimable(alice), MINIMUM_STAKE); - } - - function test_slashPermissionsZeroAndOwnerAccounting() public { - _registerAndStake(alice, 4 ether); - - vm.prank(owner); - vm.expectRevert("only rollup contract"); - submitter.slash(alice); - assertEq(rollupMock.slash(submitter, address(0)), 0); - - uint256 rollupBefore = address(rollupMock).balance; - assertEq(rollupMock.slash(submitter, alice), 1 ether); - assertEq(address(rollupMock).balance - rollupBefore, 1 ether); - assertEq(submitter.slashRemaining(), 3 ether); - assertEq(address(submitter).balance, 3 ether); - - uint256 ownerBefore = owner.balance; - vm.prank(owner); - submitter.claimSlashRemaining(owner); - assertEq(owner.balance - ownerBefore, 3 ether); - assertEq(submitter.slashRemaining(), 0); - } - - function test_parameterUpdatesValidateBoundsAndPermissions() public { - vm.prank(alice); - vm.expectRevert("Ownable: caller is not the owner"); - submitter.updateChallengeDeposit(3 ether); - - vm.startPrank(owner); - vm.expectRevert("invalid minimum stake"); - submitter.setMinimumStake(0); - vm.expectRevert("invalid challenge deposit"); - submitter.updateChallengeDeposit(CHALLENGE_DEPOSIT); - vm.expectRevert("invalid reward percentage"); - submitter.updateRewardPercentage(101); - submitter.updateChallengeDeposit(3 ether); - submitter.updateRewardPercentage(50); - vm.stopPrank(); - - assertEq(submitter.challengeDeposit(), 3 ether); - assertEq(submitter.rewardPercentage(), 50); - } - - function testFuzz_accountingConservation(uint96 aliceStake, uint96 bobStake) public { - aliceStake = uint96(bound(aliceStake, MINIMUM_STAKE, 20 ether)); - bobStake = uint96(bound(bobStake, MINIMUM_STAKE, 20 ether)); - _registerAndStake(alice, aliceStake); - _registerAndStake(bob, bobStake); - - RejectEther reject = new RejectEther(); - vm.prank(alice); - submitter.withdraw(address(reject)); - rollupMock.slash(submitter, bob); - - uint256 tracked = submitter.stakeOf(alice) + submitter.stakeOf(bob); - tracked += submitter.claimable(alice) + submitter.claimable(bob); - tracked += submitter.slashRemaining(); - assertLe(tracked, address(submitter).balance); - } - - function _registerAndStake(address actor, uint256 amount) internal { - vm.prank(owner); - submitter.addSubmitter(actor); - vm.prank(actor); - submitter.stake{value: amount}(); - } - - function _expectProxyInitializationRevert( - address owner_, - address rollup_, - uint256 minimumStake_, - uint256 deposit_, - uint256 percentage_, - string memory reason - ) internal { - Submitter freshImplementation = new Submitter(); - vm.expectRevert(bytes(reason)); - new TransparentUpgradeableProxy( - address(freshImplementation), - proxyAdmin, - abi.encodeCall(Submitter.initialize, (owner_, rollup_, minimumStake_, deposit_, percentage_)) - ); - } -} diff --git a/contracts/contracts/test/base/L1MessageBase.t.sol b/contracts/contracts/test/base/L1MessageBase.t.sol index 0cd82ba51..d2fa9db4e 100644 --- a/contracts/contracts/test/base/L1MessageBase.t.sol +++ b/contracts/contracts/test/base/L1MessageBase.t.sol @@ -7,20 +7,23 @@ import {CommonTest} from "./CommonTest.t.sol"; import {Whitelist} from "../../libraries/common/Whitelist.sol"; import {L1CrossDomainMessenger} from "../../l1/L1CrossDomainMessenger.sol"; import {L1MessageQueueWithGasPriceOracle} from "../../l1/rollup/L1MessageQueueWithGasPriceOracle.sol"; -import {Submitter} from "../../l1/rollup/Submitter.sol"; +import {L1Staking} from "../../l1/staking/L1Staking.sol"; import {Rollup} from "../../l1/rollup/Rollup.sol"; import {IRollup} from "../../l1/rollup/IRollup.sol"; import {BatchHeaderCodecV0} from "../../libraries/codec/BatchHeaderCodecV0.sol"; import {MockZkEvmVerifier} from "../../mock/MockZkEvmVerifier.sol"; contract L1MessageBaseTest is CommonTest { - // Submitter config - Submitter public submitter; - Submitter public submitterImpl; + // Staking config + L1Staking public l1Staking; + L1Staking public l1StakingImpl; uint256 public constant STAKING_VALUE = 1e18; // 1 eth uint256 public constant CHALLENGE_DEPOSIT = 1e18; // 1 eth + uint256 public constant LOCK_BLOCKS = 3; uint256 public rewardPercentage = 20; + uint32 public defaultGasLimitAdd = 1000000; + uint32 public defaultGasLimitRemove = 10000000; // Rollup config Rollup public rollup; @@ -89,14 +92,6 @@ contract L1MessageBaseTest is CommonTest { ); } - function _registerAndStakeSubmitter(address account) internal { - hevm.deal(account, 5 * STAKING_VALUE); - hevm.prank(multisig); - submitter.addSubmitter(account); - hevm.prank(account); - submitter.stake{value: STAKING_VALUE}(); - } - /// @dev Build V0 batch header for commitBatchWithProof (blob = ZERO_VERSIONED_HASH). function _createBatchHeaderV0ForProof( uint256 batchIndex, @@ -149,7 +144,7 @@ contract L1MessageBaseTest is CommonTest { address(multisig), new bytes(0) ); - TransparentUpgradeableProxy submitterProxy = new TransparentUpgradeableProxy( + TransparentUpgradeableProxy l1StakingProxy = new TransparentUpgradeableProxy( address(emptyContract), address(multisig), new bytes(0) @@ -163,7 +158,7 @@ contract L1MessageBaseTest is CommonTest { address(alice) ); l1CrossDomainMessengerImpl = new L1CrossDomainMessenger(); - submitterImpl = new Submitter(); + l1StakingImpl = new L1Staking(payable(l1CrossDomainMessengerProxy)); // upgrade and initialize ITransparentUpgradeableProxy(address(rollupProxy)).upgradeToAndCall( @@ -171,7 +166,7 @@ contract L1MessageBaseTest is CommonTest { abi.encodeCall( Rollup.initialize, ( - address(submitterProxy), + address(l1StakingProxy), address(l1MessageQueueWithGasPriceOracleProxy), // _messageQueue address(verifier), // _verifier finalizationPeriodSeconds, // _finalizationPeriodSeconds @@ -201,16 +196,18 @@ contract L1MessageBaseTest is CommonTest { ) ) ); - ITransparentUpgradeableProxy(address(submitterProxy)).upgradeToAndCall( - address(submitterImpl), + ITransparentUpgradeableProxy(address(l1StakingProxy)).upgradeToAndCall( + address(l1StakingImpl), abi.encodeCall( - Submitter.initialize, + L1Staking.initialize, ( - multisig, address(rollupProxy), STAKING_VALUE, CHALLENGE_DEPOSIT, - rewardPercentage + LOCK_BLOCKS, + rewardPercentage, + defaultGasLimitAdd, + defaultGasLimitRemove ) ) ); @@ -220,9 +217,9 @@ contract L1MessageBaseTest is CommonTest { l1MessageQueueWithGasPriceOracle = L1MessageQueueWithGasPriceOracle( address(l1MessageQueueWithGasPriceOracleProxy) ); - submitter = Submitter(payable(address(submitterProxy))); + l1Staking = L1Staking(address(l1StakingProxy)); - _changeAdmin(address(submitter)); + _changeAdmin(address(l1Staking)); _changeAdmin(address(rollup)); _changeAdmin(address(l1CrossDomainMessenger)); _changeAdmin(address(l1MessageQueueWithGasPriceOracle)); diff --git a/contracts/deploy/013-DeployProxys.ts b/contracts/deploy/013-DeployProxys.ts index 35dd0a2ab..6b3a4a5ce 100644 --- a/contracts/deploy/013-DeployProxys.ts +++ b/contracts/deploy/013-DeployProxys.ts @@ -47,7 +47,7 @@ export const deployContractProxies = async ( ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName + const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -106,9 +106,9 @@ export const deployContractProxies = async ( return err } - // ************************ batch submitter contract deploy ************************ - // SubmitterProxy deploy - err = await deployContractProxyByStorageName(hre, path, deployer, SubmitterProxyStorageName) + // ************************ staking contracts deploy ************************ + // StakingProxy deploy + err = await deployContractProxyByStorageName(hre, path, deployer, L1StakingProxyStorageName) if (err != "") { return err } @@ -281,7 +281,7 @@ export const deployContractProxiesConcurrently = async ( const proxyStorageNames = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.SubmitterProxyStorageName, + ProxyStorageName.L1StakingProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, diff --git a/contracts/deploy/014-DeployImpls.ts b/contracts/deploy/014-DeployImpls.ts index f095e1258..b32613018 100644 --- a/contracts/deploy/014-DeployImpls.ts +++ b/contracts/deploy/014-DeployImpls.ts @@ -23,7 +23,7 @@ export const deployContractImplsConcurrently = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const SubmitterFactoryName = ContractFactoryName.Submitter + const L1StakingFactoryName = ContractFactoryName.L1Staking const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -41,7 +41,7 @@ export const deployContractImplsConcurrently = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName + const StakingImplStorageName = ImplStorageName.L1StakingStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -80,6 +80,18 @@ export const deployContractImplsConcurrently = async ( await contract.deployed() console.log("%s=%s ; TX_HASH: %s", storageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); + if (factoryName == L1StakingFactoryName) { + await assertContractVariable( + contract, + 'MESSENGER', + L1CrossDomainMessengerProxyAddress + ) + await assertContractVariable( + contract, + 'OTHER_STAKING', + predeploys.L2Staking.toLowerCase() + ) + } const blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) console.log(`Deployment completed for: ${storageName}`); @@ -108,7 +120,7 @@ export const deployContractImplsConcurrently = async ( deployPromises.push(deployContract(L1ERC721GatewayFactoryName, L1ERC721GatewayImplStorageName)) deployPromises.push(deployContract(L1ERC1155GatewayFactoryName, L1ERC1155GatewayImplStorageName)) - deployPromises.push(deployContract(SubmitterFactoryName, SubmitterImplStorageName)) + deployPromises.push(deployContract(L1StakingFactoryName, StakingImplStorageName, [L1CrossDomainMessengerProxyAddress])) // L1Sequencer deploy (no constructor args) const L1SequencerFactoryName = ContractFactoryName.L1Sequencer @@ -139,7 +151,7 @@ export const deployContractImpls = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const SubmitterFactoryName = ContractFactoryName.Submitter + const L1StakingFactoryName = ContractFactoryName.L1Staking const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -157,7 +169,7 @@ export const deployContractImpls = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName + const StakingImplStorageName = ImplStorageName.L1StakingStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -352,14 +364,25 @@ export const deployContractImpls = async ( return err } - // ************************ batch submitter contract deploy ************************ - Factory = await hre.ethers.getContractFactory(SubmitterFactoryName) - contract = await Factory.deploy() + // ************************ staking contracts deploy ************************ + // Staking deploy + Factory = await hre.ethers.getContractFactory(L1StakingFactoryName) + contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", SubmitterImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); + console.log("%s=%s ; TX_HASH: %s", StakingImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); + await assertContractVariable( + contract, + 'MESSENGER', + L1CrossDomainMessengerProxyAddress + ) + await assertContractVariable( + contract, + 'OTHER_STAKING', + predeploys.L2Staking.toLowerCase() + ) blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) - err = await storage(path, SubmitterImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) + err = await storage(path, StakingImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) if (err != '') { return err } diff --git a/contracts/deploy/015-SubmitterInstall.ts b/contracts/deploy/015-SubmitterInstall.ts deleted file mode 100644 index 871824c42..000000000 --- a/contracts/deploy/015-SubmitterInstall.ts +++ /dev/null @@ -1,109 +0,0 @@ -import "@nomiclabs/hardhat-ethers"; - -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { ethers } from "ethers"; - -import { getContractAddressByName, storage } from "../src/deploy-utils"; -import { ContractFactoryName, ImplStorageName, ProxyStorageName } from "../src/types"; - -const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; - -export const SubmitterInstall = async ( - hre: HardhatRuntimeEnvironment, - path: string, - deployer: any, - config: any -): Promise => { - try { - const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); - const implementationAddress = getContractAddressByName(path, ImplStorageName.SubmitterStorageName); - const emptyImplementation = getContractAddressByName(path, ImplStorageName.EmptyContract); - const rollupAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName); - const owner = config.submitterOwner || config.contractAdmin; - const minimumStake = config.submitterMinimumStake; - const challengeDeposit = config.submitterChallengeDeposit; - const rewardPercentage = config.submitterRewardPercentage; - const plannedSubmitters: string[] = config.batchSubmitterAddresses || []; - - if ( - !ethers.utils.isAddress(proxyAddress) || - !ethers.utils.isAddress(implementationAddress) || - !ethers.utils.isAddress(rollupAddress) || - !ethers.utils.isAddress(owner) || - !(minimumStake > 0) || - !(challengeDeposit > 0) || - !(rewardPercentage > 0 && rewardPercentage <= 100) || - !Array.isArray(plannedSubmitters) || - plannedSubmitters.some((address) => !ethers.utils.isAddress(address)) - ) { - return "invalid Submitter install configuration"; - } - - const proxy = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - proxyAddress, - deployer - ); - const currentImplementation = await proxy.implementation(); - if (currentImplementation.toLowerCase() !== implementationAddress.toLowerCase()) { - if (currentImplementation.toLowerCase() !== emptyImplementation.toLowerCase()) { - return `Submitter proxy has unexpected implementation ${currentImplementation}`; - } - const factory = await hre.ethers.getContractFactory(ContractFactoryName.Submitter); - const initializer = factory.interface.encodeFunctionData("initialize", [ - owner, - rollupAddress, - hre.ethers.utils.parseEther(minimumStake.toString()), - hre.ethers.utils.parseEther(challengeDeposit.toString()), - rewardPercentage, - ]); - const response = await proxy.upgradeToAndCall(implementationAddress, initializer); - await response.wait(); - } - - // A transparent proxy admin cannot call business getters. Use a non-admin eth_call sender. - const reader = hre.ethers.Wallet.createRandom().connect(hre.ethers.provider); - const submitter = await hre.ethers.getContractAt(ContractFactoryName.Submitter, proxyAddress, reader); - if ((await submitter.owner()).toLowerCase() !== owner.toLowerCase()) { - return "Submitter owner verification failed"; - } - if ((await submitter.rollupContract()).toLowerCase() !== rollupAddress.toLowerCase()) { - return "Submitter rollup binding verification failed"; - } - if (!(await submitter.minimumStake()).eq(hre.ethers.utils.parseEther(minimumStake.toString()))) { - return "Submitter minimum stake verification failed"; - } - if (!(await submitter.challengeDeposit()).eq(hre.ethers.utils.parseEther(challengeDeposit.toString()))) { - return "Submitter challenge deposit verification failed"; - } - if (!(await submitter.rewardPercentage()).eq(rewardPercentage)) { - return "Submitter reward percentage verification failed"; - } - for (const account of plannedSubmitters) { - if ((await submitter.registered(account)) || !(await submitter.stakeOf(account)).isZero()) { - return `Submitter ${account} must remain unregistered and unstaked before Rollup cutover`; - } - } - - const rawImplementation = await hre.ethers.provider.getStorageAt(proxyAddress, IMPLEMENTATION_SLOT); - const implementationInSlot = ethers.utils.getAddress(ethers.utils.hexDataSlice(rawImplementation, 12)); - if (implementationInSlot.toLowerCase() !== implementationAddress.toLowerCase()) { - return "Submitter EIP-1967 implementation slot verification failed"; - } - const implementationCode = await hre.ethers.provider.getCode(implementationAddress); - if (implementationCode === "0x") return "Submitter implementation has no code"; - const blockNumber = await hre.ethers.provider.getBlockNumber(); - return storage(path, ImplStorageName.SubmitterInstallStorageName, proxyAddress.toLowerCase(), blockNumber, { - implementationSlot: IMPLEMENTATION_SLOT, - implementation: implementationAddress.toLowerCase(), - implementationCodeHash: ethers.utils.keccak256(implementationCode), - rollupContract: rollupAddress.toLowerCase(), - owner: owner.toLowerCase(), - }); - } catch (error) { - console.error("Submitter install failed", error); - return error instanceof Error ? error.message : "Submitter install failed"; - } -}; - -export default SubmitterInstall; diff --git a/contracts/deploy/016-RollupInit.ts b/contracts/deploy/016-RollupInit.ts index 9043d2b34..82036f186 100644 --- a/contracts/deploy/016-RollupInit.ts +++ b/contracts/deploy/016-RollupInit.ts @@ -23,7 +23,7 @@ export const RollupInit = async ( // Load the contracts we need to interact with. const ZkEvmVerifierV1Address = getContractAddressByName(path, ImplStorageName.ZkEvmVerifierV1StorageName) const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName(path, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName) - const SubmitterProxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName) + const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) // Rollup config const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) @@ -60,7 +60,7 @@ export const RollupInit = async ( if (!ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || !ethers.utils.isAddress(MultipleVersionRollupVerifierContract.address) - || !ethers.utils.isAddress(SubmitterProxyAddress) + || !ethers.utils.isAddress(L1StakingProxyAddress) ) { console.error('please check your address') @@ -70,7 +70,7 @@ export const RollupInit = async ( await IRollupProxy.upgradeToAndCall( RollupImplAddress, RollupFactory.interface.encodeFunctionData('initialize', [ - SubmitterProxyAddress, + L1StakingProxyAddress, L1MessageQueueWithGasPriceOracleProxyAddress, MultipleVersionRollupVerifierContract.address, finalizationPeriodSeconds, @@ -97,8 +97,8 @@ export const RollupInit = async ( ) await assertContractVariable( contractTmp, - 'submitterContract', - SubmitterProxyAddress + 'l1StakingContract', + L1StakingProxyAddress ) await assertContractVariable( contractTmp, diff --git a/contracts/deploy/018-StakingInit.ts b/contracts/deploy/018-StakingInit.ts new file mode 100644 index 000000000..5cf151a42 --- /dev/null +++ b/contracts/deploy/018-StakingInit.ts @@ -0,0 +1,128 @@ +import "@nomiclabs/hardhat-web3"; +import "@nomiclabs/hardhat-ethers"; +import "@nomiclabs/hardhat-waffle"; + +import { + HardhatRuntimeEnvironment +} from 'hardhat/types'; +import { assertContractVariable, getContractAddressByName, awaitCondition } from "../src/deploy-utils"; +import { ethers } from 'ethers' + +import { + ImplStorageName, + ProxyStorageName, + ContractFactoryName, +} from "../src/types" + +export const StakingInit = async ( + hre: HardhatRuntimeEnvironment, + path: string, + deployer: any, + configTmp: any +): Promise => { + // Load the contracts we need to interact with. + const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) + + // Staking config + const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const L1StakingImplAddress = getContractAddressByName(path, ImplStorageName.L1StakingStorageName) + const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) + + const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) + if ( + (await IL1StakingProxy.implementation()).toLocaleLowerCase() !== L1StakingImplAddress.toLocaleLowerCase() + ) { + console.log('Upgrading the Staking proxy...') + const admin: string = configTmp.contractAdmin + const stakingChallengerRewardPercentage: number = configTmp.stakingChallengerRewardPercentage + const limit: number = configTmp.stakingMinDeposit + const challengeDeposit: number = configTmp.stakingChallengeDeposit + const lock: number = configTmp.stakingLockNumber + const gasLimitAdd: number = configTmp.stakingCrossChainGaslimitAdd + const gasLimitRemove: number = configTmp.stakingCrossChainGaslimitRemove + + if (!ethers.utils.isAddress(admin) + || lock <= 0 + || limit <= 0 + || challengeDeposit <= 0 + || gasLimitAdd <= 0 + || gasLimitRemove <= 0 + || stakingChallengerRewardPercentage > 100 + || stakingChallengerRewardPercentage <= 0 + ) { + console.error('please check your address') + return '' + } + + // Upgrade and initialize the proxy. + await IL1StakingProxy.upgradeToAndCall( + L1StakingImplAddress, + L1StakingFactory.interface.encodeFunctionData('initialize', [ + RollupProxyAddress, + hre.ethers.utils.parseEther(limit.toString()), + hre.ethers.utils.parseEther(challengeDeposit.toString()), + lock.toString(), + stakingChallengerRewardPercentage, + gasLimitAdd, + gasLimitRemove, + ]) + ) + + await awaitCondition( + async () => { + return ( + (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() + ) + }, + 3000, + 1000 + ) + + const contractTmp = new ethers.Contract( + L1StakingProxyAddress, + L1StakingFactory.interface, + deployer, + ) + + await assertContractVariable( + contractTmp, + 'rollupContract', + RollupProxyAddress + ) + await assertContractVariable( + contractTmp, + 'rewardPercentage', + stakingChallengerRewardPercentage + ) + await assertContractVariable( + contractTmp, + 'stakingValue', + hre.ethers.utils.parseEther(limit.toString()) + ) + await assertContractVariable( + contractTmp, + 'withdrawalLockBlocks', + lock.toString() + ) + await assertContractVariable( + contractTmp, + 'gasLimitAddStaker', + gasLimitAdd + ) + await assertContractVariable( + contractTmp, + 'gasLimitRemoveStakers', + gasLimitRemove + ) + await assertContractVariable( + contractTmp, + 'owner', + await deployer.getAddress(), + ) + // Wait for the transaction to execute properly. + console.log('StakingProxy upgrade success') + } + return '' +} + +export default StakingInit diff --git a/contracts/deploy/019-AdminTransfer.ts b/contracts/deploy/019-AdminTransfer.ts index 491248494..a0cd1b58a 100644 --- a/contracts/deploy/019-AdminTransfer.ts +++ b/contracts/deploy/019-AdminTransfer.ts @@ -108,7 +108,7 @@ export const AdminTransferConcurrently = async ( const contractsToChange = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.SubmitterProxyStorageName, + ProxyStorageName.L1StakingProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, // Added L1Sequencer ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, @@ -159,7 +159,7 @@ export const AdminTransfer = async ( const L1MessageQueueWithGasPriceOracleProxyStorageName = ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName + const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -187,9 +187,9 @@ export const AdminTransfer = async ( return err } - // ************************ batch submitter contract admin change ************************ - // SubmitterProxy admin change - err = await AdminTransferByProxyStorageName(hre, path, deployer, SubmitterProxyStorageName) + // ************************ staking contracts admin change ************************ + // StakingProxy admin change + err = await AdminTransferByProxyStorageName(hre, path, deployer, L1StakingProxyStorageName) if (err != '') { return err } diff --git a/contracts/deploy/020-ContractInit.ts b/contracts/deploy/020-ContractInit.ts index 22ed49663..96bf3637b 100644 --- a/contracts/deploy/020-ContractInit.ts +++ b/contracts/deploy/020-ContractInit.ts @@ -31,6 +31,20 @@ export const ContractInit = async ( let rec = await res.wait() console.log(`set base fee ${rec.status === 1} setL2BaseFee(${await GasPriceOracle.l2BaseFee()}) gwei`) + const WhitelistImplAddress = getContractAddressByName(path, ImplStorageName.Whitelist) + const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) + let addList = [L1StakingProxyAddress] + res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) + rec = await res.wait() + for (let i = 0; i < addList.length; i++) { + let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) + if (res != true) { + console.error('whitelist check failed') + return '' + } + } + console.log(`add ${addList} to whitelist success`) } // ------------------ rollup init ----------------- @@ -40,11 +54,14 @@ export const ContractInit = async ( // import genesis batch const batchHeader: string = config.batchHeader - // challenger + // submitter and challenger + const submitter: string = config.rollupProposer const challenger: string = config.rollupChallenger const rollupDelayPeriod: number = config.rollupDelayPeriod - if (!ethers.utils.isAddress(challenger)) { + if (!ethers.utils.isAddress(submitter) + || !ethers.utils.isAddress(challenger) + ) { console.error('please check your address') return '' } @@ -68,6 +85,29 @@ export const ContractInit = async ( console.log(`initialize3(%s) ${rec.status == 1 ? "success" : "failed"}`) } + // ------------------ staking init ----------------- + { + const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) + const whiteListAdd = config.l2SequencerAddresses + console.log("Add sequencer address to white list ", config.l2SequencerAddresses) + // set sequencer to white list + await L1Staking.updateWhitelist(whiteListAdd, []) + for (let i = 0; i < config.l2SequencerAddresses.length; i++) { + // Wait for the transaction to execute properly. + await awaitCondition( + async () => { + return ( + await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true + ) + }, + 3000, + 1000 + ) + console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) + } + } + // ------------------ router init ----------------- { const L1WETHAddress = getContractAddressByName(path, ImplStorageName.WETH) diff --git a/contracts/deploy/021-StakingRegister.ts b/contracts/deploy/021-StakingRegister.ts new file mode 100644 index 000000000..9e69e0bf8 --- /dev/null +++ b/contracts/deploy/021-StakingRegister.ts @@ -0,0 +1,57 @@ +import "@nomiclabs/hardhat-web3"; +import "@nomiclabs/hardhat-ethers"; +import "@nomiclabs/hardhat-waffle"; + +import { + HardhatRuntimeEnvironment +} from 'hardhat/types'; +import { getContractAddressByName, awaitCondition } from "../src/deploy-utils"; +import { ethers } from 'ethers' +import { + ProxyStorageName, + ContractFactoryName, +} from "../src/types" + +const two = BigInt(2) +const gwei = BigInt(1e9) +const eth = gwei * gwei + +export const StakingRegister = async ( + hre: HardhatRuntimeEnvironment, + path: string, + signer: any, + tmKey: string, + blsKey: string +): Promise => { + const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) + + const StakingProxyWithSigner = new ethers.Contract( + L1StakingProxyAddress, + L1StakingFactory.interface, + signer, + ) + + // just for devnet register value may set params to config + const response = await StakingProxyWithSigner.register(tmKey, blsKey, { + value: eth + }) + console.log(`Transaction hash (on L1): ${response.hash}`) + const receipt = await response.wait() + console.log('Transaction in L1 height', receipt.blockNumber) + + await awaitCondition( + async () => { + const sequencerInfo = (await StakingProxyWithSigner.stakers(signer.address)) + if (sequencerInfo && sequencerInfo.tmKey === tmKey) { + return true + } + return false + }, + 30000, + 1000 + ) + return '' +} + +export default StakingRegister \ No newline at end of file diff --git a/contracts/deploy/021-SubmitterRegister.ts b/contracts/deploy/021-SubmitterRegister.ts deleted file mode 100644 index 76a71b524..000000000 --- a/contracts/deploy/021-SubmitterRegister.ts +++ /dev/null @@ -1,38 +0,0 @@ -import "@nomiclabs/hardhat-ethers"; - -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { ethers } from "ethers"; - -import { getContractAddressByName } from "../src/deploy-utils"; -import { ContractFactoryName, ProxyStorageName } from "../src/types"; - -export const SubmitterRegister = async ( - hre: HardhatRuntimeEnvironment, - path: string, - ownerSigner: any, - submitterSigner: any -): Promise => { - const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); - if (!ethers.utils.isAddress(proxyAddress)) return "invalid Submitter proxy address"; - - const ownerView = await hre.ethers.getContractAt(ContractFactoryName.Submitter, proxyAddress, ownerSigner); - const account = await submitterSigner.getAddress(); - if ((await ownerView.owner()).toLowerCase() !== (await ownerSigner.getAddress()).toLowerCase()) { - return "registration signer is not Submitter owner"; - } - if (!(await ownerView.registered(account))) { - await (await ownerView.addSubmitter(account)).wait(); - } - - const submitterView = ownerView.connect(submitterSigner); - const minimumStake = await submitterView.minimumStake(); - const currentStake = await submitterView.stakeOf(account); - if (currentStake.lt(minimumStake)) { - await (await submitterView.stake({ value: minimumStake.sub(currentStake) })).wait(); - } - if (!(await submitterView.isActive(account))) return "Submitter did not become active"; - console.log(`Submitter ${account} registered and active with stake ${await submitterView.stakeOf(account)}`); - return ""; -}; - -export default SubmitterRegister; diff --git a/contracts/deploy/index.ts b/contracts/deploy/index.ts index b0d41da05..a30ab90fb 100644 --- a/contracts/deploy/index.ts +++ b/contracts/deploy/index.ts @@ -3,13 +3,13 @@ import deployEmptyContract from './011-EmptyContract' import {deployContractProxies,deployContractProxiesConcurrently} from './013-DeployProxys' import deployZkEvmVerifierV1 from './012-Verifier' import {deployContractImpls, deployContractImplsConcurrently} from './014-DeployImpls' -import SubmitterInstall from './015-SubmitterInstall' import MessengerInit from './015-MessengerInit' import RollupInit from './016-RollupInit' import GatewayInit from './017-GatewayInit' +import StakingInit from './018-StakingInit' import {AdminTransfer,AdminTransferByProxyStorageName, AdminTransferConcurrently} from './019-AdminTransfer' import ContractInit from './020-ContractInit' -import SubmitterRegister from './021-SubmitterRegister' +import StakingRegister from './021-StakingRegister' import SequencerInit from './022-SequencerInit' @@ -21,14 +21,14 @@ export { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, - SubmitterInstall, MessengerInit, RollupInit, GatewayInit, + StakingInit, AdminTransfer, AdminTransferByProxyStorageName, AdminTransferConcurrently, ContractInit, - SubmitterRegister, + StakingRegister, SequencerInit -} +} \ No newline at end of file diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index af8adc51b..c60bf6ec7 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -9,11 +9,13 @@ import fs from "fs" import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from "hardhat/builtin-tasks/task-names"; import { subtask } from "hardhat/config"; + import "./tasks/deploy" import "./tasks/overflow_test" import "./tasks/check" import "./tasks/query" import "./tasks/proxy_upgrade" +import "./tasks/staking_upgrade" import "./tasks/verifier_upgrade" import "./tasks/token_deploy" import "./tasks/mainnet_upgrade" @@ -49,9 +51,7 @@ module.exports = { abiExporter: { path: './abi', runOnCompile: true, - // The immutable pre-submitter and legacy retirement ABIs live under abi/archive. - // Never let a routine current-ABI export erase those cutover artifacts. - clear: false, + clear: true, }, bytecodeExporter: { path: './data', @@ -156,4 +156,4 @@ module.exports = { artifacts: "./artifacts", deployConfig: './src/deploy-config', } -} +} \ No newline at end of file diff --git a/contracts/integration-test/retire-l1-staking.spec.ts b/contracts/integration-test/retire-l1-staking.spec.ts deleted file mode 100644 index f7eabd5b0..000000000 --- a/contracts/integration-test/retire-l1-staking.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { expect } from "chai"; -import { BigNumber, ethers } from "ethers"; - -import { - ReplayEvent, - RetirementManifest, - rebuildLegacyState, - retirementBlockers, - verifyExecutePreconditions, -} from "../scripts/retire-l1-staking"; - -const alice = "0x00000000000000000000000000000000000000a1"; -const bob = "0x00000000000000000000000000000000000000b2"; - -function event( - blockNumber: number, - blockHash: string, - name: string, - args: Record, - logIndex = 0 -): ReplayEvent { - return { - blockNumber, - blockHash, - transactionHash: `0x${blockNumber.toString(16).padStart(64, "0")}`, - logIndex, - name, - args, - }; -} - -function manifest(): RetirementManifest { - return { - version: 1, - legacy: { - proxy: "0x0000000000000000000000000000000000000100", - deployBlock: 1, - deployBlockHash: "0x01", - proxyAdminIsDedicated: false, - burnAdmin: "0x000000000000000000000000000000000000dEaD", - }, - retirement: { confirmations: 1, stakingValue: "100", treasury: alice }, - snapshot: { - chainId: 1, - safeHead: 10, - safeHeadHash: "0x10", - stakingValue: "100", - contractBalance: "0", - expectedLiabilities: "0", - unexplainedBalance: "0", - slashRemaining: "0", - owner: alice, - activeStakers: [], - }, - candidates: [], - canonicalEventIds: [], - checkpoints: [], - relays: [], - operations: [], - }; -} - -describe("legacy L1Staking retirement planning", () => { - it("aborts when stakingValue changes during the withdrawal window", () => { - const plan = manifest(); - expect(() => verifyExecutePreconditions(plan, { stakingValue: BigNumber.from(101) })).to.throw( - "stakingValue changed during retirement" - ); - }); - - it("rebuilds ever-whitelisted state from the canonical branch after a short reorg", () => { - const orphanHash = `0x${"aa".repeat(32)}`; - const canonicalHash = `0x${"bb".repeat(32)}`; - const events = [ - event(10, orphanHash, "WhitelistUpdated", { add: [alice], remove: [] }), - event(10, canonicalHash, "WhitelistUpdated", { add: [bob], remove: [] }), - event(10, canonicalHash, "Registered", { addr: bob }, 1), - event(10, canonicalHash, "Withdrawn", { addr: bob }, 2), - event(10, canonicalHash, "StakersRemoved", { stakers: [bob] }, 3), - ]; - - const rebuilt = rebuildLegacyState(events, { 10: canonicalHash }); - expect(rebuilt.candidates.map((candidate) => candidate.address)).to.deep.equal([ethers.utils.getAddress(bob)]); - expect(rebuilt.candidates[0].everRegistered).to.equal(true); - expect(rebuilt.candidates[0].withdrawn).to.equal(true); - expect(rebuilt.candidates[0].removed).to.equal(true); - expect(rebuilt.canonicalEventIds).to.have.length(4); - }); - - it("blocks owner/admin retirement until whitelist, withdrawals, relays, and admin scope are clean", () => { - const plan = manifest(); - plan.candidates = [ - { - address: alice, - everRegistered: true, - withdrawn: true, - claimed: false, - slashed: false, - removed: true, - currentWhitelist: true, - currentActive: false, - withdrawalUnlockBlock: "12", - }, - ]; - plan.relays = [ - { - messageHash: "0x01", - addresses: [alice], - transactionHash: "0x02", - blockHash: "0x03", - success: false, - canonical: false, - }, - ]; - expect(retirementBlockers(plan)).to.include.members([ - `${alice}: whitelist still enabled`, - `${alice}: withdrawal still pending`, - "0x01: removeStakers relay incomplete", - "legacy proxy admin is not confirmed dedicated", - ]); - }); -}); diff --git a/contracts/integration-test/submitter-deploy.spec.ts b/contracts/integration-test/submitter-deploy.spec.ts deleted file mode 100644 index b713ea961..000000000 --- a/contracts/integration-test/submitter-deploy.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { expect } from "chai"; -import { ethers } from "hardhat"; - -const EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"; - -describe("Submitter deployment order", () => { - it("installs and initializes Submitter before Rollup and admin transfer", async () => { - const [proxyAdminSigner, submitterOwner, other] = await ethers.getSigners(); - const empty = await (await ethers.getContractFactory("EmptyContract")).deploy(); - const proxyFactory = await ethers.getContractFactory("TransparentUpgradeableProxy"); - const rollupProxy = await proxyFactory.deploy(empty.address, proxyAdminSigner.address, "0x"); - const submitterProxy = await proxyFactory.deploy(empty.address, proxyAdminSigner.address, "0x"); - const submitterImpl = await (await ethers.getContractFactory("Submitter")).deploy(); - const rollupImpl = await (await ethers.getContractFactory("Rollup")).deploy(53077); - - const proxyAdminView = await ethers.getContractAt( - "ITransparentUpgradeableProxy", - submitterProxy.address, - proxyAdminSigner - ); - const submitterFactory = await ethers.getContractFactory("Submitter"); - await proxyAdminView.upgradeToAndCall( - submitterImpl.address, - submitterFactory.interface.encodeFunctionData("initialize", [ - submitterOwner.address, - rollupProxy.address, - ethers.utils.parseEther("1"), - ethers.utils.parseEther("1"), - 20, - ]) - ); - expect(await proxyAdminView.implementation()).to.equal(submitterImpl.address); - - const submitter = await ethers.getContractAt("Submitter", submitterProxy.address, submitterOwner); - expect(await submitter.owner()).to.equal(submitterOwner.address); - expect(await submitter.rollupContract()).to.equal(rollupProxy.address); - await expect( - submitter.initialize( - submitterOwner.address, - rollupProxy.address, - ethers.utils.parseEther("1"), - ethers.utils.parseEther("1"), - 20 - ) - ).to.be.revertedWith("Initializable: contract is already initialized"); - - const rollupProxyAdminView = await ethers.getContractAt( - "ITransparentUpgradeableProxy", - rollupProxy.address, - proxyAdminSigner - ); - const rollupFactory = await ethers.getContractFactory("Rollup"); - await rollupProxyAdminView.upgradeToAndCall( - rollupImpl.address, - rollupFactory.interface.encodeFunctionData("initialize", [ - submitterProxy.address, - other.address, - other.address, - 10, - 100, - 70, - ]) - ); - const rollup = await ethers.getContractAt("Rollup", rollupProxy.address, submitterOwner); - expect(await rollup.submitterContract()).to.equal(submitterProxy.address); - - const proxyAdmin = await (await ethers.getContractFactory("ProxyAdmin")).deploy(); - await proxyAdminView.changeAdmin(proxyAdmin.address); - const rawAdmin = await ethers.provider.getStorageAt(submitterProxy.address, EIP1967_ADMIN_SLOT); - expect(ethers.utils.getAddress(ethers.utils.hexDataSlice(rawAdmin, 12))).to.equal(proxyAdmin.address); - }); -}); diff --git a/contracts/ops/legacy-l1-staking-retirement.example.json b/contracts/ops/legacy-l1-staking-retirement.example.json deleted file mode 100644 index c338e09f9..000000000 --- a/contracts/ops/legacy-l1-staking-retirement.example.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "legacy": { - "proxy": "0x0000000000000000000000000000000000000000", - "deployBlock": 0, - "proxyAdminIsDedicated": false, - "burnAdmin": "0x000000000000000000000000000000000000dEaD" - }, - "retirement": { - "confirmations": 64, - "treasury": "0x0000000000000000000000000000000000000000" - }, - "candidates": [], - "canonicalEventIds": [], - "checkpoints": [], - "relays": [], - "operations": [] -} diff --git a/contracts/package.json b/contracts/package.json index 7bf7d938c..810c56de1 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -23,10 +23,9 @@ "test": "yarn test:hardhat && yarn test:forge", "clean": "yarn clean:build && yarn clean:compile && yarn clean:tsc", "clean:build": "rm -rf ./dist ./cache ./cache-hardhat ./node_modules ./logs", - "clean:compile": "rm -rf ./idea ./forge_artifacts ./artifacts ./typechain-types ./forge-artifacts && node scripts/clean-generated-abi.js", + "clean:compile": "rm -rf ./idea ./forge_artifacts ./abi ./artifacts ./typechain-types ./forge-artifacts", "clean:tsc": "rm -rf ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts", "typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'", - "verify:abi-archive": "node scripts/verify-abi-archive.js", "deploy:devnetL1": "rm -f devnetL1.json && hardhat deploy --network l1 --storagepath devnetL1.json", "initialize:devnetL1": "hardhat initialize --network l1 --storagepath devnetL1.json", "register:devnetL1": "hardhat register --network l1 --storagepath devnetL1.json", diff --git a/contracts/scripts/clean-generated-abi.js b/contracts/scripts/clean-generated-abi.js deleted file mode 100644 index c43402d14..000000000 --- a/contracts/scripts/clean-generated-abi.js +++ /dev/null @@ -1,16 +0,0 @@ -const fs = require('fs') -const path = require('path') - -const { archiveDir, verifyAbiArchive } = require('./verify-abi-archive') - -verifyAbiArchive() - -const abiDir = path.dirname(archiveDir) -for (const entry of fs.readdirSync(abiDir, { withFileTypes: true })) { - if (entry.name === path.basename(archiveDir)) { - continue - } - fs.rmSync(path.join(abiDir, entry.name), { recursive: true, force: true }) -} - -verifyAbiArchive() diff --git a/contracts/scripts/retire-l1-staking.ts b/contracts/scripts/retire-l1-staking.ts deleted file mode 100644 index e3371c1e6..000000000 --- a/contracts/scripts/retire-l1-staking.ts +++ /dev/null @@ -1,664 +0,0 @@ -import { createHash } from "crypto"; -import fs from "fs"; -import path from "path"; - -import { BigNumber, Contract, Wallet, ethers } from "ethers"; - -const ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"; -const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; -const ZERO_ADDRESS = ethers.constants.AddressZero; - -export type RetirementMode = "plan" | "dry-run" | "execute" | "verify"; - -export interface ReplayEvent { - name: string; - args: Record; - blockNumber: number; - blockHash: string; - transactionHash: string; - logIndex: number; -} - -export interface CandidateState { - address: string; - firstEvent?: string; - lastEvent?: string; - everRegistered: boolean; - withdrawn: boolean; - claimed: boolean; - slashed: boolean; - removed: boolean; - currentWhitelist?: boolean; - currentActive?: boolean; - withdrawalUnlockBlock?: string; -} - -export interface RetirementOperation { - kind: "freeze" | "withdraw" | "claim" | "claim-slash" | "renounce-owner" | "burn-admin"; - actor: string; - target: string; - value: string; - data: string; - description: string; - nonce?: number; - expectedState: string[]; - txHash?: string; - receiptBlockHash?: string; -} - -export interface RelayEvidence { - messageHash: string; - addresses?: string[]; - transactionHash: string; - blockHash: string; - success: boolean; - canonical: boolean; -} - -export interface RetirementManifest { - version: number; - legacy: { - proxy: string; - implementation?: string; - deployBlock: number; - deployBlockHash?: string; - proxyAdmin?: string; - proxyAdminOwner?: string; - proxyAdminIsDedicated: boolean; - burnAdmin: string; - }; - retirement: { - confirmations: number; - stakingValue?: string; - treasury: string; - }; - snapshot?: { - chainId: number; - safeHead: number; - safeHeadHash: string; - stakingValue: string; - contractBalance: string; - expectedLiabilities: string; - unexplainedBalance: string; - slashRemaining: string; - owner: string; - activeStakers: string[]; - }; - candidates: CandidateState[]; - canonicalEventIds: string[]; - checkpoints: Array<{ blockNumber: number; blockHash: string }>; - relays: RelayEvidence[]; - operations: RetirementOperation[]; - verifiedAt?: string; -} - -function normalizeAddress(value: string): string { - return ethers.utils.getAddress(value); -} - -function eventId(event: ReplayEvent): string { - return `${event.blockHash}:${event.transactionHash}:${event.logIndex}`; -} - -function eventAddresses(value: unknown): string[] { - if (!Array.isArray(value)) return []; - return value.filter((item): item is string => typeof item === "string").map(normalizeAddress); -} - -/** - * Rebuilds state from scratch against canonical block hashes. Rebuilding instead of appending - * means orphaned tip events disappear automatically after an L1 reorg. - */ -export function rebuildLegacyState( - events: ReplayEvent[], - canonicalBlockHashes: Record -): { candidates: CandidateState[]; canonicalEventIds: string[] } { - const candidates = new Map(); - const canonicalEventIds: string[] = []; - - const get = (address: string, identity: string): CandidateState => { - const normalized = normalizeAddress(address); - const key = normalized.toLowerCase(); - let state = candidates.get(key); - if (!state) { - state = { - address: normalized, - firstEvent: identity, - lastEvent: identity, - everRegistered: false, - withdrawn: false, - claimed: false, - slashed: false, - removed: false, - }; - candidates.set(key, state); - } - state.lastEvent = identity; - return state; - }; - - for (const event of [...events].sort((a, b) => a.blockNumber - b.blockNumber || a.logIndex - b.logIndex)) { - const canonicalHash = canonicalBlockHashes[event.blockNumber]; - if (!canonicalHash || canonicalHash.toLowerCase() !== event.blockHash.toLowerCase()) continue; - const identity = eventId(event); - canonicalEventIds.push(identity); - - if (event.name === "WhitelistUpdated") { - for (const address of eventAddresses(event.args.add)) get(address, identity); - for (const address of eventAddresses(event.args.remove)) get(address, identity); - } else if (event.name === "Registered") { - const state = get(String(event.args.addr), identity); - state.everRegistered = true; - state.withdrawn = false; - state.claimed = false; - state.slashed = false; - state.removed = false; - } else if (event.name === "Withdrawn") { - get(String(event.args.addr), identity).withdrawn = true; - } else if (event.name === "Claimed") { - const state = get(String(event.args.staker), identity); - state.claimed = true; - state.withdrawn = false; - } else if (event.name === "Slashed") { - for (const address of eventAddresses(event.args.stakers)) { - const state = get(address, identity); - state.slashed = true; - state.removed = true; - } - } else if (event.name === "StakersRemoved") { - for (const address of eventAddresses(event.args.stakers)) get(address, identity).removed = true; - } - } - - return { - candidates: [...candidates.values()].sort((a, b) => a.address.localeCompare(b.address)), - canonicalEventIds, - }; -} - -export function verifyExecutePreconditions( - manifest: RetirementManifest, - current: { stakingValue: BigNumber | string; deployBlockHash?: string } -): void { - if (!manifest.retirement.stakingValue) throw new Error("retirement stakingValue snapshot missing"); - if (!BigNumber.from(current.stakingValue).eq(manifest.retirement.stakingValue)) { - throw new Error("stakingValue changed during retirement"); - } - if ( - manifest.legacy.deployBlockHash && - current.deployBlockHash && - manifest.legacy.deployBlockHash.toLowerCase() !== current.deployBlockHash.toLowerCase() - ) { - throw new Error("legacy deployment block is no longer canonical"); - } -} - -export function retirementBlockers(manifest: RetirementManifest): string[] { - const blockers: string[] = []; - if (!manifest.snapshot) return ["snapshot missing"]; - for (const candidate of manifest.candidates) { - if (candidate.currentWhitelist) blockers.push(`${candidate.address}: whitelist still enabled`); - if (candidate.currentActive) blockers.push(`${candidate.address}: staker still active`); - if (BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0)) { - blockers.push(`${candidate.address}: withdrawal still pending`); - } - } - if (!BigNumber.from(manifest.snapshot.slashRemaining).isZero()) blockers.push("slashRemaining is nonzero"); - if (!BigNumber.from(manifest.snapshot.contractBalance).isZero()) blockers.push("legacy contract balance is nonzero"); - for (const relay of manifest.relays) { - if (!relay.success || !relay.canonical) blockers.push(`${relay.messageHash}: removeStakers relay incomplete`); - } - for (const candidate of manifest.candidates.filter( - (item) => item.removed || item.withdrawn || item.slashed - )) { - const covered = manifest.relays.some( - (relay) => - relay.success && - relay.canonical && - (relay.addresses || []).some( - (address) => address.toLowerCase() === candidate.address.toLowerCase() - ) - ); - if (!covered) blockers.push(`${candidate.address}: canonical removeStakers relay evidence missing`); - } - if (!manifest.legacy.proxyAdminIsDedicated) blockers.push("legacy proxy admin is not confirmed dedicated"); - return blockers; -} - -function archivedAbiPath(): string { - return path.resolve(__dirname, "../abi/archive/legacy-l1-staking/L1Staking.json"); -} - -function loadFrozenAbi(): unknown[] { - const abiPath = archivedAbiPath(); - const archiveManifestPath = path.resolve(__dirname, "../abi/archive/manifest.json"); - if (!fs.existsSync(abiPath) || !fs.existsSync(archiveManifestPath)) { - throw new Error("frozen legacy L1Staking ABI archive is missing"); - } - const raw = fs.readFileSync(abiPath); - const archiveManifest = JSON.parse(fs.readFileSync(archiveManifestPath, "utf8")); - const expected = archiveManifest.artifacts?.["legacy-l1-staking/L1Staking.json"]; - const actual = createHash("sha256").update(raw).digest("hex"); - if (!expected || actual !== expected) throw new Error("frozen legacy L1Staking ABI hash mismatch"); - return JSON.parse(raw.toString("utf8")); -} - -function addressFromSlot(raw: string): string { - return normalizeAddress(ethers.utils.hexDataSlice(raw, 12)); -} - -async function collectCanonicalEvents( - provider: ethers.providers.Provider, - contractAddress: string, - deployBlock: number, - safeHead: number, - abi: unknown[] -): Promise<{ events: ReplayEvent[]; hashes: Record; checkpoints: RetirementManifest["checkpoints"] }> { - const iface = new ethers.utils.Interface(abi); - const logs = await provider.getLogs({ address: contractAddress, fromBlock: deployBlock, toBlock: safeHead }); - const blockNumbers = [...new Set([deployBlock, safeHead, ...logs.map((log) => log.blockNumber)])]; - const blocks = await Promise.all(blockNumbers.map((number) => provider.getBlock(number))); - const hashes: Record = {}; - const checkpoints: RetirementManifest["checkpoints"] = []; - for (const block of blocks) { - if (!block) throw new Error("canonical block lookup failed"); - hashes[block.number] = block.hash; - checkpoints.push({ blockNumber: block.number, blockHash: block.hash }); - } - - const events: ReplayEvent[] = []; - for (const log of logs) { - try { - const parsed = iface.parseLog(log); - if (!["WhitelistUpdated", "Registered", "Withdrawn", "Claimed", "Slashed", "StakersRemoved"].includes(parsed.name)) { - continue; - } - const args: Record = {}; - for (const [key, value] of Object.entries(parsed.args)) { - if (!/^\d+$/.test(key)) args[key] = value; - } - events.push({ - name: parsed.name, - args, - blockNumber: log.blockNumber, - blockHash: log.blockHash, - transactionHash: log.transactionHash, - logIndex: log.logIndex, - }); - } catch { - // The proxy may emit unrelated proxy-admin events; the frozen business ABI does not parse them. - } - } - return { events, hashes, checkpoints }; -} - -async function refreshManifest( - provider: ethers.providers.JsonRpcProvider, - manifest: RetirementManifest, - abi: unknown[] -): Promise { - const latest = await provider.getBlockNumber(); - const safeHead = latest - manifest.retirement.confirmations; - if (safeHead < manifest.legacy.deployBlock) throw new Error("safe head precedes legacy deployment"); - const chain = await provider.getNetwork(); - const contract = new Contract(manifest.legacy.proxy, abi, provider); - const replay = await collectCanonicalEvents(provider, manifest.legacy.proxy, manifest.legacy.deployBlock, safeHead, abi); - const rebuilt = rebuildLegacyState(replay.events, replay.hashes); - const activeStakers: string[] = (await contract.getActiveStakers({ blockTag: safeHead })).map(normalizeAddress); - const candidateMap = new Map(rebuilt.candidates.map((candidate) => [candidate.address.toLowerCase(), candidate])); - for (const address of activeStakers) { - if (!candidateMap.has(address.toLowerCase())) { - candidateMap.set(address.toLowerCase(), { - address, - everRegistered: true, - withdrawn: false, - claimed: false, - slashed: false, - removed: false, - }); - } - } - const candidates = [...candidateMap.values()].sort((a, b) => a.address.localeCompare(b.address)); - for (const candidate of candidates) { - const [whitelist, active, withdrawal] = await Promise.all([ - contract.whitelist(candidate.address, { blockTag: safeHead }), - contract.isActiveStaker(candidate.address, { blockTag: safeHead }), - contract.withdrawals(candidate.address, { blockTag: safeHead }), - ]); - candidate.currentWhitelist = whitelist; - candidate.currentActive = active; - candidate.withdrawalUnlockBlock = withdrawal.toString(); - } - - const [stakingValue, slashRemaining, owner, balance] = await Promise.all([ - contract.stakingValue({ blockTag: safeHead }), - contract.slashRemaining({ blockTag: safeHead }), - contract.owner({ blockTag: safeHead }), - provider.getBalance(manifest.legacy.proxy, safeHead), - ]); - const liabilityCount = candidates.filter( - (candidate) => candidate.currentActive || BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0) - ).length; - const expectedLiabilities = stakingValue.mul(liabilityCount).add(slashRemaining); - const unexplainedBalance = balance.gt(expectedLiabilities) ? balance.sub(expectedLiabilities) : BigNumber.from(0); - const safeBlock = await provider.getBlock(safeHead); - const deployBlock = await provider.getBlock(manifest.legacy.deployBlock); - if (!safeBlock || !deployBlock) throw new Error("snapshot block lookup failed"); - - const rawAdmin = await provider.getStorageAt(manifest.legacy.proxy, ADMIN_SLOT, safeHead); - const rawImplementation = await provider.getStorageAt(manifest.legacy.proxy, IMPLEMENTATION_SLOT, safeHead); - manifest.legacy.proxyAdmin = addressFromSlot(rawAdmin); - manifest.legacy.implementation = addressFromSlot(rawImplementation); - manifest.legacy.deployBlockHash = deployBlock.hash; - if (!manifest.retirement.stakingValue) manifest.retirement.stakingValue = stakingValue.toString(); - verifyExecutePreconditions(manifest, { stakingValue, deployBlockHash: deployBlock.hash }); - - manifest.snapshot = { - chainId: chain.chainId, - safeHead, - safeHeadHash: safeBlock.hash, - stakingValue: stakingValue.toString(), - contractBalance: balance.toString(), - expectedLiabilities: expectedLiabilities.toString(), - unexplainedBalance: unexplainedBalance.toString(), - slashRemaining: slashRemaining.toString(), - owner: normalizeAddress(owner), - activeStakers, - }; - manifest.candidates = candidates; - manifest.canonicalEventIds = rebuilt.canonicalEventIds; - manifest.checkpoints = replay.checkpoints; - manifest.operations = await buildOperations(provider, contract, manifest, abi); - return manifest; -} - -async function buildOperations( - provider: ethers.providers.Provider, - contract: Contract, - manifest: RetirementManifest, - abi: unknown[] -): Promise { - if (!manifest.snapshot) throw new Error("snapshot missing"); - const iface = new ethers.utils.Interface(abi); - const owner = manifest.snapshot.owner; - const operations: RetirementOperation[] = []; - const whitelisted = manifest.candidates.filter((candidate) => candidate.currentWhitelist).map((candidate) => candidate.address); - if (whitelisted.length > 0) { - operations.push({ - kind: "freeze", - actor: owner, - target: manifest.legacy.proxy, - value: "0", - data: iface.encodeFunctionData("updateWhitelist", [[], whitelisted]), - description: `remove ${whitelisted.length} canonical ever-whitelisted address(es) from whitelist`, - expectedState: whitelisted.map((address) => `whitelist(${address}) == false`), - }); - } - for (const candidate of manifest.candidates) { - if (candidate.currentActive) { - operations.push({ - kind: "withdraw", - actor: candidate.address, - target: manifest.legacy.proxy, - value: "0", - data: iface.encodeFunctionData("withdraw"), - description: `withdraw legacy stake for ${candidate.address}`, - expectedState: [ - `isActiveStaker(${candidate.address}) == false`, - `withdrawals(${candidate.address}) > 0`, - ], - }); - } else if ( - BigNumber.from(candidate.withdrawalUnlockBlock || 0).gt(0) && - BigNumber.from(candidate.withdrawalUnlockBlock || 0).lte(manifest.snapshot.safeHead) - ) { - operations.push({ - kind: "claim", - actor: candidate.address, - target: manifest.legacy.proxy, - value: "0", - data: iface.encodeFunctionData("claimWithdrawal", [candidate.address]), - description: `claim matured legacy withdrawal for ${candidate.address}`, - expectedState: [`withdrawals(${candidate.address}) == 0`], - }); - } - } - if (!BigNumber.from(manifest.snapshot.slashRemaining).isZero()) { - operations.push({ - kind: "claim-slash", - actor: owner, - target: manifest.legacy.proxy, - value: "0", - data: iface.encodeFunctionData("claimSlashRemaining", [manifest.retirement.treasury]), - description: "reconcile legacy slashRemaining to retirement treasury", - expectedState: ["slashRemaining() == 0"], - }); - } - - if (retirementBlockers(manifest).length === 0 && owner !== ZERO_ADDRESS) { - operations.push({ - kind: "renounce-owner", - actor: owner, - target: manifest.legacy.proxy, - value: "0", - data: iface.encodeFunctionData("renounceOwnership"), - description: "renounce legacy L1Staking business ownership", - expectedState: [`owner() == ${ZERO_ADDRESS}`], - }); - const admin = normalizeAddress(manifest.legacy.proxyAdmin || ZERO_ADDRESS); - if (admin === ZERO_ADDRESS || admin.toLowerCase() === manifest.legacy.burnAdmin.toLowerCase()) { - return assignOperationNonces(provider, operations); - } - const adminCode = await provider.getCode(admin); - if (adminCode === "0x") { - const proxyIface = new ethers.utils.Interface(["function changeAdmin(address newAdmin)"]); - operations.push({ - kind: "burn-admin", - actor: admin, - target: manifest.legacy.proxy, - value: "0", - data: proxyIface.encodeFunctionData("changeAdmin", [manifest.legacy.burnAdmin]), - description: "move the dedicated legacy proxy admin to the configured burn address", - expectedState: [`proxy admin == ${manifest.legacy.burnAdmin}`], - }); - } else { - const proxyAdmin = new Contract(admin, ["function owner() view returns (address)"], provider); - manifest.legacy.proxyAdminOwner = normalizeAddress( - await proxyAdmin.owner({ blockTag: manifest.snapshot.safeHead }) - ); - const proxyAdminIface = new ethers.utils.Interface([ - "function changeProxyAdmin(address proxy,address newAdmin)", - ]); - operations.push({ - kind: "burn-admin", - actor: manifest.legacy.proxyAdminOwner, - target: admin, - value: "0", - data: proxyAdminIface.encodeFunctionData("changeProxyAdmin", [ - manifest.legacy.proxy, - manifest.legacy.burnAdmin, - ]), - description: "detach only the legacy proxy from its confirmed-dedicated ProxyAdmin", - expectedState: [`proxy admin == ${manifest.legacy.burnAdmin}`], - }); - } - } - return assignOperationNonces(provider, operations); -} - -async function assignOperationNonces( - provider: ethers.providers.Provider, - operations: RetirementOperation[] -): Promise { - const nextNonce = new Map(); - for (const operation of operations) { - const actor = operation.actor.toLowerCase(); - let nonce = nextNonce.get(actor); - if (nonce === undefined) nonce = await provider.getTransactionCount(operation.actor, "pending"); - operation.nonce = nonce; - nextNonce.set(actor, nonce + 1); - } - return operations; -} - -function signerMap(provider: ethers.providers.JsonRpcProvider): Map { - const keys: string[] = JSON.parse(process.env.RETIRE_SIGNER_KEYS || "[]"); - const result = new Map(); - for (const key of keys) { - const wallet = new Wallet(key, provider); - result.set(wallet.address.toLowerCase(), wallet); - } - return result; -} - -async function executeOperations( - provider: ethers.providers.JsonRpcProvider, - manifest: RetirementManifest, - manifestPath: string, - abi: unknown[] -): Promise { - if (process.env.RETIRE_CONFIRM_EXECUTE !== "YES") { - throw new Error("execute mode requires RETIRE_CONFIRM_EXECUTE=YES"); - } - if (!manifest.snapshot) throw new Error("snapshot missing"); - const contract = new Contract(manifest.legacy.proxy, abi, provider); - const deployBlock = await provider.getBlock(manifest.legacy.deployBlock); - verifyExecutePreconditions(manifest, { - stakingValue: await contract.stakingValue(), - deployBlockHash: deployBlock?.hash, - }); - if (manifest.operations.some((operation) => operation.kind === "renounce-owner" || operation.kind === "burn-admin")) { - const [active, balance, slashRemaining] = await Promise.all([ - contract.getActiveStakers(), - provider.getBalance(manifest.legacy.proxy), - contract.slashRemaining(), - ]); - if (active.length > 0 || !balance.isZero() || !slashRemaining.isZero()) { - throw new Error("irreversible retirement gate changed after planning"); - } - for (const candidate of manifest.candidates) { - const [whitelisted, withdrawal] = await Promise.all([ - contract.whitelist(candidate.address), - contract.withdrawals(candidate.address), - ]); - if (whitelisted || !withdrawal.isZero()) { - throw new Error(`irreversible retirement gate changed for ${candidate.address}`); - } - } - } - const signers = signerMap(provider); - for (const operation of manifest.operations) { - if (!signers.has(operation.actor.toLowerCase())) { - throw new Error(`missing signer for ${operation.kind} actor ${operation.actor}`); - } - if (!Number.isSafeInteger(operation.nonce) || operation.nonce! < 0) { - throw new Error(`missing deterministic nonce for ${operation.kind} actor ${operation.actor}`); - } - } - // Resolve every actor and nonce before broadcasting so execution never partially applies a stale plan. - const firstNonceByActor = new Map(); - for (const operation of manifest.operations) { - const actor = operation.actor.toLowerCase(); - if (!firstNonceByActor.has(actor)) firstNonceByActor.set(actor, operation.nonce!); - } - for (const [actor, nonce] of firstNonceByActor) { - const current = await provider.getTransactionCount(actor, "pending"); - if (current !== nonce) throw new Error(`planned nonce changed for ${actor}: expected ${nonce}, got ${current}`); - } - for (const operation of manifest.operations) { - const signer = signers.get(operation.actor.toLowerCase())!; - const response = await signer.sendTransaction({ - to: operation.target, - data: operation.data, - value: BigNumber.from(operation.value), - nonce: operation.nonce, - }); - const receipt = await response.wait(); - if (receipt.status !== 1) throw new Error(`${operation.kind} transaction failed`); - operation.txHash = receipt.transactionHash; - operation.receiptBlockHash = receipt.blockHash; - fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); - } -} - -async function dryRunOperations( - provider: ethers.providers.JsonRpcProvider, - manifest: RetirementManifest -): Promise { - if (!manifest.snapshot) throw new Error("snapshot missing"); - for (const operation of manifest.operations) { - try { - await provider.call( - { - from: operation.actor, - to: operation.target, - data: operation.data, - value: BigNumber.from(operation.value), - }, - manifest.snapshot.safeHead - ); - } catch (error) { - throw new Error( - `dry-run simulation failed for ${operation.kind} (${operation.description}): ${ - error instanceof Error ? error.message : String(error) - }` - ); - } - } -} - -async function verifyRelayEvidence( - provider: ethers.providers.Provider, - relays: RelayEvidence[] -): Promise { - for (const relay of relays) { - if (!relay.transactionHash) continue; - const receipt = await provider.getTransactionReceipt(relay.transactionHash); - relay.success = Boolean(receipt && receipt.status === 1); - relay.canonical = Boolean(receipt && receipt.blockHash.toLowerCase() === relay.blockHash.toLowerCase()); - } -} - -function parseArgs(): { mode: RetirementMode; manifestPath: string } { - const mode = (process.env.RETIRE_MODE || process.argv[2] || "plan") as RetirementMode; - if (!["plan", "dry-run", "execute", "verify"].includes(mode)) throw new Error(`invalid mode ${mode}`); - const manifestPath = path.resolve(process.env.RETIRE_MANIFEST || process.argv[3] || "legacy-l1-staking-retirement.json"); - return { mode, manifestPath }; -} - -async function main(): Promise { - const { mode, manifestPath } = parseArgs(); - if (!process.env.L1_RPC_URL) throw new Error("L1_RPC_URL is required"); - if (!fs.existsSync(manifestPath)) throw new Error(`retirement manifest not found: ${manifestPath}`); - const provider = new ethers.providers.JsonRpcProvider(process.env.L1_RPC_URL); - const manifest: RetirementManifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); - if ( - !ethers.utils.isAddress(manifest.legacy.proxy) || - manifest.legacy.proxy === ZERO_ADDRESS || - !ethers.utils.isAddress(manifest.legacy.burnAdmin) || - manifest.legacy.burnAdmin === ZERO_ADDRESS || - !ethers.utils.isAddress(manifest.retirement.treasury) - ) { - throw new Error("retirement manifest contains invalid addresses"); - } - const abi = loadFrozenAbi(); - await verifyRelayEvidence(provider, manifest.relays); - await refreshManifest(provider, manifest, abi); - - console.log(JSON.stringify({ mode, snapshot: manifest.snapshot, operations: manifest.operations }, null, 2)); - if (mode === "dry-run") await dryRunOperations(provider, manifest); - if (mode === "execute") await executeOperations(provider, manifest, manifestPath, abi); - if (mode === "verify") { - const blockers = retirementBlockers(manifest); - if (blockers.length > 0) throw new Error(`retirement verification blocked:\n${blockers.join("\n")}`); - manifest.verifiedAt = new Date().toISOString(); - } - fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); -} - -if (require.main === module) { - main().catch((error) => { - console.error(error); - process.exitCode = 1; - }); -} diff --git a/contracts/scripts/verify-abi-archive.js b/contracts/scripts/verify-abi-archive.js deleted file mode 100644 index db6527658..000000000 --- a/contracts/scripts/verify-abi-archive.js +++ /dev/null @@ -1,36 +0,0 @@ -const crypto = require('crypto') -const fs = require('fs') -const path = require('path') - -const archiveDir = path.resolve(__dirname, '..', 'abi', 'archive') -const manifestPath = path.join(archiveDir, 'manifest.json') - -function verifyAbiArchive() { - if (!fs.existsSync(manifestPath)) { - throw new Error(`frozen ABI manifest is missing: ${manifestPath}`) - } - - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) - for (const [relativePath, expectedHash] of Object.entries(manifest.artifacts)) { - const artifactPath = path.resolve(archiveDir, relativePath) - if (!fs.existsSync(artifactPath)) { - throw new Error(`frozen ABI artifact is missing: ${artifactPath}`) - } - const actualHash = crypto - .createHash('sha256') - .update(fs.readFileSync(artifactPath)) - .digest('hex') - if (actualHash !== expectedHash) { - throw new Error( - `frozen ABI hash mismatch for ${relativePath}: expected ${expectedHash}, got ${actualHash}` - ) - } - } -} - -if (require.main === module) { - verifyAbiArchive() - console.log('Frozen ABI archive hashes verified') -} - -module.exports = { archiveDir, verifyAbiArchive } diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index 3624dcb1b..353d9ced9 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -23,16 +23,22 @@ const config = { proofRewardPercent: 70, // challenge config // TODO to be removed later - batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], + rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', rollupChallenger: '0x48445d5DDb25a4f23C6d85D87f15B39Fe94e6867', // genesis config rollupGenesisStateRoot: '', - // submitter initialize config - submitterChallengeDeposit: 1, // 1 ether - submitterMinimumStake: 1, // 1 ether - submitterRewardPercentage: 100, + // staking config + // staking Cross-Chain config + stakingCrossChainGaslimitAdd: 1000000, + stakingCrossChainGaslimitRemove: 8000000, + + // staking initialize config + stakingLockNumber: 3, + stakingChallengeDeposit: 1, // 1 ether + stakingMinDeposit: 1, // 1 ether + stakingChallengerRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index 31db491e5..d589f50a6 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -24,16 +24,22 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], + rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', rollupChallenger: '0x2910DB00C9537B90337b40D9732f4c356cbb84D0', // genesis config batchHeader: '00000000000000000000000000000000000000000000000000aa0feb482ae04f2a6b6b422932b5a2d537cd657ceb83008e87fce6ed6d290031010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000000a31941eb1853862c0c38f378eb0c519e9e66f0942e39b47dca38c0437ab6b3e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // submitter initialize config - submitterChallengeDeposit: 1, // 1 ether - submitterMinimumStake: 1, // 1 ether - submitterRewardPercentage: 100, + // staking config + // staking Cross-Chain config + stakingCrossChainGaslimitAdd: 1000000, + stakingCrossChainGaslimitRemove: 8000000, + + // staking initialize config + stakingLockNumber: 3, + stakingChallengeDeposit: 1, // 1 ether + stakingMinDeposit: 1, // 1 ether + stakingChallengerRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index 12525b6af..285ca9c59 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -26,15 +26,21 @@ const config = { rollupDelayPeriod: 86400, // challenge config - batchSubmitterAddresses: ['0x70997970C51812dc3A010C7d01b50e0d17dc79C8'], + rollupProposer: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', rollupChallenger: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65', // genesis config batchHeader: '0x00000000000000000000000000000000000000000000000000886e14341b355178d11a2c9f985f60a1a195973078b688a11aeaebb0c95db595010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000002d20dde82426d971e398b3cba11ebb60d0d740b799f85e2f95fd12a1faad8e2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // submitter initialize config - submitterChallengeDeposit: 1, // 1 ether - submitterMinimumStake: 1, // 1 ether - submitterRewardPercentage: 100, + // staking config + // staking Cross-Chain config + stakingCrossChainGaslimitAdd: 1000000, + stakingCrossChainGaslimitRemove: 8000000, + + // staking initialize config + stakingLockNumber: 3, + stakingChallengeDeposit: 1, // 1 ether + stakingMinDeposit: 1, // 1 ether + stakingChallengerRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x783698dCDEBdc96785c5c60ED96113612bA09c2b", diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index abbc0b834..b0740d0b9 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -21,15 +21,21 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - batchSubmitterAddresses: ['0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d'], + rollupProposer: '0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d', rollupChallenger: '0x71616250f7CAaa8a5DC295dc5851D6b1E49188a7', // genesis config batchHeader: '', - // submitter initialize config - submitterChallengeDeposit: 1, // 1 ether - submitterMinimumStake: 1, // 1 ether - submitterRewardPercentage: 50, + // staking config + // staking Cross-Chain config + stakingCrossChainGaslimitAdd: 1000000, + stakingCrossChainGaslimitRemove: 8000000, + + // staking initialize config + stakingLockNumber: 3, + stakingChallengeDeposit: 1, // 1 ether + stakingMinDeposit: 1, // 1 ether + stakingChallengerRewardPercentage: 50, // register sequencers l2SequencerAddresses: [ "0x25d36d94b64165f72a817ae0ff9bad2ce6914c70", diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 849ff3fe2..3657c5811 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -22,16 +22,16 @@ const config = { rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, - batchSubmitterAddresses: ['0x77774B33aFa9Ecef8835D25ff749ff84950e83af'], + rollupProposer: '0x77774B33aFa9Ecef8835D25ff749ff84950e83af', rollupChallenger: '0x77776ab9Ed7479Ff446f1E3135145e245f2B71B1', rollupGenesisStateRoot: '', withdrawRoot: '', batchHeader: '', finalizationPeriodSeconds: 600, - submitterMinimumStake: 0.1, - submitterChallengeDeposit: 0.1, - submitterRewardPercentage: 100, + stakingSequencerSize: 7, + stakingLockNumber: 3, + stakingMinDeposit: 0.1, baseFeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', l1FeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index af76da02b..8e0c9786f 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -18,14 +18,14 @@ const config = { rollupProofWindow: 100, rollupGenesisBlockNumber: 0, proofRewardPercent: 70, - batchSubmitterAddresses: ['0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3'], + rollupProposer: '0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3', rollupChallenger: '0xF730477971E88b3162ed7FD950Be63474975bdC3', rollupGenesisStateRoot: '', finalizationPeriodSeconds: 2, - submitterMinimumStake: 1, - submitterChallengeDeposit: 1, - submitterRewardPercentage: 100, + stakingMinDeposit: 1, + stakingSequencerSize: 3, + stakingLockNumber: 3, /** * Only used for SystemConfig * --------from-------- diff --git a/contracts/src/deploy-utils.ts b/contracts/src/deploy-utils.ts index 8a1a2d8b3..ddb59efe5 100644 --- a/contracts/src/deploy-utils.ts +++ b/contracts/src/deploy-utils.ts @@ -114,14 +114,12 @@ export const storage = async ( contractsName: string, contractAddress: string, deployedBlockNumber: number, - metadata: Record = {}, ): Promise => { let Contract = { name: contractsName, address: contractAddress, time: new Date().toISOString(), - number: deployedBlockNumber, - ...metadata, + number: deployedBlockNumber } if (fs.existsSync(path)) { let data = fs.readFileSync(path) @@ -172,3 +170,4 @@ export const sleep = async (ms: number): Promise => { }, ms); }); }; + diff --git a/contracts/src/types.ts b/contracts/src/types.ts index 74574ddf2..7e518addd 100644 --- a/contracts/src/types.ts +++ b/contracts/src/types.ts @@ -16,8 +16,8 @@ const ContractFactoryName = { Rollup: 'Rollup', ZkEvmVerifierV1: 'ZkEvmVerifierV1', MultipleVersionRollupVerifier: 'MultipleVersionRollupVerifier', - // batch submitter - Submitter: 'Submitter', + // staking + L1Staking: 'L1Staking', // L1 sequencer L1Sequencer: 'L1Sequencer', // gateway @@ -40,8 +40,8 @@ const ProxyStorageName = { L1MessageQueueWithGasPriceOracleProxyStorageName: 'Proxy__L1MessageQueueWithGasPriceOracle', // rollup RollupProxyStorageName: 'Proxy__Rollup', - // batch submitter - SubmitterProxyStorageName: 'Proxy__Submitter', + // staking + L1StakingProxyStorageName: 'Proxy__L1Staking', // L1 sequencer L1SequencerProxyStorageName: 'Proxy__L1Sequencer', // gateway @@ -73,9 +73,8 @@ const ImplStorageName = { RollupStorageName: 'Impl__Rollup', ZkEvmVerifierV1StorageName: 'Impl__ZkEvmVerifierV1', MultipleVersionRollupVerifierStorageName: 'Impl__MultipleVersionRollupVerifier', - // batch submitter - SubmitterStorageName: 'Impl__Submitter', - SubmitterInstallStorageName: 'Install__Submitter', + // staking + L1StakingStorageName: 'Impl__L1Staking', // L1 sequencer L1SequencerStorageName: 'Impl__L1Sequencer', // gateway @@ -96,4 +95,4 @@ export { ImplStorageName, ProxyStorageName, ContractFactoryName -} +} \ No newline at end of file diff --git a/contracts/storage-layout/archive/Rollup.pre-submitter.json b/contracts/storage-layout/archive/Rollup.pre-submitter.json deleted file mode 100644 index 847c1cf90..000000000 --- a/contracts/storage-layout/archive/Rollup.pre-submitter.json +++ /dev/null @@ -1,424 +0,0 @@ -{ - "storage": [ - { - "astId": 123005, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8" - }, - { - "astId": 123008, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool" - }, - { - "astId": 125558, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage" - }, - { - "astId": 122758, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "_owner", - "offset": 0, - "slot": "51", - "type": "t_address" - }, - { - "astId": 122878, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "__gap", - "offset": 0, - "slot": "52", - "type": "t_array(t_uint256)49_storage" - }, - { - "astId": 123189, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "_paused", - "offset": 0, - "slot": "101", - "type": "t_bool" - }, - { - "astId": 123294, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage" - }, - { - "astId": 8103, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "l1StakingContract", - "offset": 0, - "slot": "151", - "type": "t_address" - }, - { - "astId": 8106, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "finalizationPeriodSeconds", - "offset": 0, - "slot": "152", - "type": "t_uint256" - }, - { - "astId": 8109, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "proofWindow", - "offset": 0, - "slot": "153", - "type": "t_uint256" - }, - { - "astId": 8112, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "__maxNumTxInChunk", - "offset": 0, - "slot": "154", - "type": "t_uint256" - }, - { - "astId": 8115, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "messageQueue", - "offset": 0, - "slot": "155", - "type": "t_address" - }, - { - "astId": 8118, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "verifier", - "offset": 0, - "slot": "156", - "type": "t_address" - }, - { - "astId": 8122, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "lastFinalizedBatchIndex", - "offset": 0, - "slot": "157", - "type": "t_uint256" - }, - { - "astId": 8126, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "lastCommittedBatchIndex", - "offset": 0, - "slot": "158", - "type": "t_uint256" - }, - { - "astId": 8131, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "isChallenger", - "offset": 0, - "slot": "159", - "type": "t_mapping(t_address,t_bool)" - }, - { - "astId": 8137, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "finalizedStateRoots", - "offset": 0, - "slot": "160", - "type": "t_mapping(t_uint256,t_bytes32)" - }, - { - "astId": 8143, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "committedBatches", - "offset": 0, - "slot": "161", - "type": "t_mapping(t_uint256,t_bytes32)" - }, - { - "astId": 8149, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "batchDataStore", - "offset": 0, - "slot": "162", - "type": "t_mapping(t_uint256,t_struct(BatchData)6917_storage)" - }, - { - "astId": 8154, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "withdrawalRoots", - "offset": 0, - "slot": "163", - "type": "t_mapping(t_bytes32,t_bool)" - }, - { - "astId": 8160, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "challenges", - "offset": 0, - "slot": "164", - "type": "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)" - }, - { - "astId": 8165, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "batchChallengeReward", - "offset": 0, - "slot": "165", - "type": "t_mapping(t_address,t_uint256)" - }, - { - "astId": 8168, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "inChallenge", - "offset": 0, - "slot": "166", - "type": "t_bool" - }, - { - "astId": 8171, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "batchChallenged", - "offset": 0, - "slot": "167", - "type": "t_uint256" - }, - { - "astId": 8174, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "revertReqIndex", - "offset": 0, - "slot": "168", - "type": "t_uint256" - }, - { - "astId": 8177, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "proofRewardPercent", - "offset": 0, - "slot": "169", - "type": "t_uint256" - }, - { - "astId": 8180, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "proveRemaining", - "offset": 0, - "slot": "170", - "type": "t_uint256" - }, - { - "astId": 8185, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "committedStateRoots", - "offset": 0, - "slot": "171", - "type": "t_mapping(t_uint256,t_bytes32)" - }, - { - "astId": 8188, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "rollupDelayPeriod", - "offset": 0, - "slot": "172", - "type": "t_uint256" - }, - { - "astId": 8193, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "batchBlobVersionedHashes", - "offset": 0, - "slot": "173", - "type": "t_mapping(t_uint256,t_bytes32)" - } - ], - "types": { - "t_address": { - "encoding": "inplace", - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)49_storage": { - "encoding": "inplace", - "label": "uint256[49]", - "numberOfBytes": "1568", - "base": "t_uint256" - }, - "t_array(t_uint256)50_storage": { - "encoding": "inplace", - "label": "uint256[50]", - "numberOfBytes": "1600", - "base": "t_uint256" - }, - "t_bool": { - "encoding": "inplace", - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "encoding": "inplace", - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => bool)", - "numberOfBytes": "32", - "value": "t_bool" - }, - "t_mapping(t_address,t_uint256)": { - "encoding": "mapping", - "key": "t_address", - "label": "mapping(address => uint256)", - "numberOfBytes": "32", - "value": "t_uint256" - }, - "t_mapping(t_bytes32,t_bool)": { - "encoding": "mapping", - "key": "t_bytes32", - "label": "mapping(bytes32 => bool)", - "numberOfBytes": "32", - "value": "t_bool" - }, - "t_mapping(t_uint256,t_bytes32)": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => bytes32)", - "numberOfBytes": "32", - "value": "t_bytes32" - }, - "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => struct IRollup.BatchChallenge)", - "numberOfBytes": "32", - "value": "t_struct(BatchChallenge)6931_storage" - }, - "t_mapping(t_uint256,t_struct(BatchData)6917_storage)": { - "encoding": "mapping", - "key": "t_uint256", - "label": "mapping(uint256 => struct IRollup.BatchData)", - "numberOfBytes": "32", - "value": "t_struct(BatchData)6917_storage" - }, - "t_struct(BatchChallenge)6931_storage": { - "encoding": "inplace", - "label": "struct IRollup.BatchChallenge", - "numberOfBytes": "128", - "members": [ - { - "astId": 6920, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "batchIndex", - "offset": 0, - "slot": "0", - "type": "t_uint64" - }, - { - "astId": 6922, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "challenger", - "offset": 8, - "slot": "0", - "type": "t_address" - }, - { - "astId": 6924, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "challengeDeposit", - "offset": 0, - "slot": "1", - "type": "t_uint256" - }, - { - "astId": 6926, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "startTime", - "offset": 0, - "slot": "2", - "type": "t_uint256" - }, - { - "astId": 6928, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "challengeSuccess", - "offset": 0, - "slot": "3", - "type": "t_bool" - }, - { - "astId": 6930, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "finished", - "offset": 1, - "slot": "3", - "type": "t_bool" - } - ] - }, - "t_struct(BatchData)6917_storage": { - "encoding": "inplace", - "label": "struct IRollup.BatchData", - "numberOfBytes": "128", - "members": [ - { - "astId": 6910, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "originTimestamp", - "offset": 0, - "slot": "0", - "type": "t_uint256" - }, - { - "astId": 6912, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "finalizeTimestamp", - "offset": 0, - "slot": "1", - "type": "t_uint256" - }, - { - "astId": 6914, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "blockNumber", - "offset": 0, - "slot": "2", - "type": "t_uint256" - }, - { - "astId": 6916, - "contract": "contracts/l1/rollup/Rollup.sol:Rollup", - "label": "signedSequencersBitmap", - "offset": 0, - "slot": "3", - "type": "t_uint256" - } - ] - }, - "t_uint256": { - "encoding": "inplace", - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint64": { - "encoding": "inplace", - "label": "uint64", - "numberOfBytes": "8" - }, - "t_uint8": { - "encoding": "inplace", - "label": "uint8", - "numberOfBytes": "1" - } - } -} diff --git a/contracts/tasks/deploy.ts b/contracts/tasks/deploy.ts index 527f9d837..a7ea6bb6a 100644 --- a/contracts/tasks/deploy.ts +++ b/contracts/tasks/deploy.ts @@ -13,14 +13,14 @@ import { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, - SubmitterInstall, MessengerInit, RollupInit, GatewayInit, + StakingInit, AdminTransfer, AdminTransferConcurrently, ContractInit, - SubmitterRegister, + StakingRegister, SequencerInit, } from '../deploy/index' import { ethers } from "ethers"; @@ -97,13 +97,6 @@ task("initialize") return } - console.log('\n---------------------------------- Submitter install ----------------------------------') - err = await SubmitterInstall(hre, storagePath, deployer, config) - if (err != '') { - console.log('Submitter install failed, err: ', err) - return - } - console.log('\n---------------------------------- Messenger init ----------------------------------') err = await MessengerInit(hre, storagePath, deployer, config) if (err != '') { @@ -122,6 +115,12 @@ task("initialize") console.log('Rollup init failed, err: ', err) return } + console.log('\n---------------------------------- Staking init ----------------------------------') + err = await StakingInit(hre, storagePath, deployer, config) + if (err != '') { + console.log('Staking init failed, err: ', err) + return + } console.log('\n---------------------------------- Sequencer init ----------------------------------') err = await SequencerInit(hre, storagePath, deployer, config) if (err != '') { @@ -153,23 +152,25 @@ task("initialize") task("fund") .setAction(async (taskArgs, hre) => { - console.log('\n---------------------------------- Fund Submitters ----------------------------------') + console.log('\n---------------------------------- Fund Staking ----------------------------------') const signer = await hre.ethers.getSigners() - const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); - for (let i = 0; i < batchSubmitterPkList.length; i++) { - const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) + console.log(process.env.l2SequencerPks) + let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); + console.log(l2SequencerPkList) + for (let i = 0; i < l2SequencerPkList.length; i++) { + let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) const tx = { - to: submitter.address, + to: sequencer.address, value: ethers.utils.parseEther("100") } - let balance = (await submitter.getBalance()).toString() + let balance = (await sequencer.getBalance()).toString() if (balance.length < 20) { let receipt = await signer[0].sendTransaction(tx) await receipt.wait() } - balance = (await submitter.getBalance()).toString() - console.log(`${submitter.address} has balance: ${balance}`) + balance = (await sequencer.getBalance()).toString() + console.log(`${sequencer.address} has balance: ${balance}`) } }) @@ -180,19 +181,14 @@ task("register") // Initialization parameters const storagePath = taskArgs.storagepath const config = hre.deployConfig - const owner = await hre.ethers.provider.getSigner(); - const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); - const configuredAddresses: string[] = config.batchSubmitterAddresses || []; - for (let i = 0; i < batchSubmitterPkList.length; i++) { - const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) - if (configuredAddresses[i] && configuredAddresses[i].toLowerCase() !== submitter.address.toLowerCase()) { - throw new Error(`batch submitter key ${i} does not match configured address`) - } - console.log(`\n---------------------------------- register submitter-${i} ----------------------------------`) - console.log(`submitter-${i}:` + submitter.address + ', Balance: ' + await submitter.getBalance()) - const err = await SubmitterRegister(hre, storagePath, owner, submitter) + let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); + for (let i = 0; i < l2SequencerPkList.length; i++) { + let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) + console.log(`\n---------------------------------- register sequencer-${i} ----------------------------------`) + console.log(`sequencer-${i}:` + await sequencer.getAddress() + ', Balance: ' + await sequencer.getBalance()) + let err = await StakingRegister(hre, storagePath, sequencer, config.l2SequencerTmKeys[i], config.l2SequencerBlsKeys[i]) if (err != '') { - console.log(`Register Submitter-${i} failed, err: `, err) + console.log(`Deploy Staking Sequencer-${i} failed, err: `, err) return } } diff --git a/contracts/tasks/staking_upgrade.ts b/contracts/tasks/staking_upgrade.ts new file mode 100644 index 000000000..9a237e62d --- /dev/null +++ b/contracts/tasks/staking_upgrade.ts @@ -0,0 +1,901 @@ +import "@nomiclabs/hardhat-web3" +import "@nomiclabs/hardhat-ethers" +import "@nomiclabs/hardhat-waffle" + +import fs from "fs"; +import assert from "assert" +import { task } from "hardhat/config" +import { ethers } from "ethers" +import { assertContractVariable, getContractAddressByName, awaitCondition, storage } from "../src/deploy-utils" +import { ImplStorageName, ProxyStorageName, ContractFactoryName } from "../src/types" +import { predeploys } from "../src" +import { hexlify } from "ethers/lib/utils"; + +task("rollup-deploy-init") + .addParam("storagepath") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + // deploy config + const storagePath = taskArgs.storagepath + const newPath = taskArgs.newpath + const config = hre.deployConfig + const chainId = config.l2ChainID + const deployer = hre.ethers.provider.getSigner() + + const ProxyFactoryName = ContractFactoryName.DefaultProxy + const IProxyFactoryName = ContractFactoryName.DefaultProxyInterface + const RollupFactoryName = ContractFactoryName.Rollup + const RollupImplStorageName = ImplStorageName.RollupStorageName + const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName + const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) + + const RollupFactory = await hre.ethers.getContractFactory(RollupFactoryName) + const rollupNewImpl = await RollupFactory.deploy(chainId) + await rollupNewImpl.deployed() + let blockNumber = await hre.ethers.provider.getBlockNumber() + let err = await storage( + newPath, + RollupImplStorageName, + rollupNewImpl.address.toLocaleLowerCase(), + blockNumber || 0 + ) + if (err != "") { + return err + } + console.log(`Rollup new impl deploy at ${rollupNewImpl.address}`) + + // Proxy deploy + const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) + // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin + const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") + await proxy.deployed() + blockNumber = await hre.ethers.provider.getBlockNumber() + err = await storage(newPath, RollupProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) + if (err != "") { + return err + } + console.log(`Rollup proxy deploy at ${proxy.address}`) + + // ------------------ deploy MultipleVersionRollupVerifier ----------------- + { + // deploy ZkEvmVerifierV1 + const ZkEvmVerifierV1ContractFactoryName = ContractFactoryName.ZkEvmVerifierV1 + const ZkEvmVerifierV1ImplStorageName = ImplStorageName.ZkEvmVerifierV1StorageName + const Factory = await hre.ethers.getContractFactory(ZkEvmVerifierV1ContractFactoryName) + const contract = await Factory.deploy(config.programVkey) + await contract.deployed() + console.log("%s=%s ; TX_HASH: %s", ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); + let blockNumber = await hre.ethers.provider.getBlockNumber() + console.log("BLOCK_NUMBER: %s", blockNumber) + let err = await storage(newPath, ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) + if (err != '') { + return err + } + + + // deploy MultipleVersionRollupVerifier + const ZkEvmVerifierV1Address = getContractAddressByName( + newPath, + ImplStorageName.ZkEvmVerifierV1StorageName + ) + const MultipleVersionRollupVerifierFactoryName = ContractFactoryName.MultipleVersionRollupVerifier + const MultipleVersionRollupVerifierImplStorageName = + ImplStorageName.MultipleVersionRollupVerifierStorageName + console.log("Deploy the MultipleVersionRollupVerifier ...") + const MultipleVersionRollupVerifierFactory = await hre.ethers.getContractFactory( + MultipleVersionRollupVerifierFactoryName + ) + const version = [0] + const verifiers = [ZkEvmVerifierV1Address] + const MultipleVersionRollupVerifierContract = await MultipleVersionRollupVerifierFactory.deploy( + version, + verifiers + ) + await MultipleVersionRollupVerifierContract.deployed() + await MultipleVersionRollupVerifierContract.initialize(proxy.address) + console.log( + "%s=%s ; TX_HASH: %s", + MultipleVersionRollupVerifierImplStorageName, + MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), + MultipleVersionRollupVerifierContract.deployTransaction.hash + ) + blockNumber = await hre.ethers.provider.getBlockNumber() + console.log("BLOCK_NUMBER: %s", blockNumber) + err = await storage( + newPath, + MultipleVersionRollupVerifierImplStorageName, + MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), + blockNumber || 0 + ) + if (err != "") { + return err + } + } + + // ------------------ rollup initialize ----------------- + { + const IRollupProxy = await hre.ethers.getContractAt(IProxyFactoryName, proxy.address, deployer) + console.log("Upgrading the Rollup proxy...") + const finalizationPeriodSeconds: number = config.finalizationPeriodSeconds + const proofWindow: number = config.rollupProofWindow + + const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName + ) + const L1StakingProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1StakingProxyStorageName + ) + const MultipleVersionRollupVerifierContractAddress = getContractAddressByName( + newPath, + ImplStorageName.MultipleVersionRollupVerifierStorageName + ) + if ( + !ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || + !ethers.utils.isAddress(MultipleVersionRollupVerifierContractAddress) || + !ethers.utils.isAddress(L1StakingProxyAddress) + ) { + console.error("please check your address") + return "" + } + + // Upgrade and initialize the proxy. + await IRollupProxy.upgradeToAndCall( + rollupNewImpl.address, + RollupFactory.interface.encodeFunctionData("initialize", [ + L1StakingProxyAddress, + L1MessageQueueWithGasPriceOracleProxyAddress, + MultipleVersionRollupVerifierContractAddress, + finalizationPeriodSeconds, + proofWindow, + ]) + ) + + await awaitCondition( + async () => { + return ( + (await IRollupProxy.implementation()).toLocaleLowerCase() === + rollupNewImpl.address.toLocaleLowerCase() + ) + }, + 3000, + 1000 + ) + // params check + const contractTmp = new ethers.Contract(proxy.address, RollupFactory.interface, deployer) + await assertContractVariable(contractTmp, "l1StakingContract", L1StakingProxyAddress) + await assertContractVariable(contractTmp, "messageQueue", L1MessageQueueWithGasPriceOracleProxyAddress) + await assertContractVariable(contractTmp, "verifier", MultipleVersionRollupVerifierContractAddress) + await assertContractVariable(contractTmp, "finalizationPeriodSeconds", finalizationPeriodSeconds) + await assertContractVariable(contractTmp, "proofWindow", proofWindow) + await assertContractVariable(contractTmp, "owner", await deployer.getAddress()) + + // Wait for the transaction to execute properly. + console.log(`RollupProxy upgrade success, Rollup address at ${proxy.address}`) + } + + // ------------------ Admin transfer ----------------- + { + const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() + const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) + const IProxyContract = await hre.ethers.getContractAt( + ContractFactoryName.DefaultProxyInterface, + proxy.address, + deployer + ) + { + const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() + const admin = (await IProxyContract.admin()).toLocaleLowerCase() + if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { + return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` + } + if (admin !== deployerAddr) { + return `Proxy admin address ${admin} should deployer address ${deployerAddr}` + } + } + console.log(`change rollup admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) + const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) + await res.wait() + await assertContractVariable( + IProxyContract, + "admin", + ProxyAdminImplAddr, + ProxyAdminImplAddr // caller + ) + console.log(`admin transfer successful`) + } + }) + +task("rollup-import-genesis-batch") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + // deploy config + const newPath = taskArgs.newpath + const config = hre.deployConfig + const deployer = hre.ethers.provider.getSigner() + // ------------------ rollup import genesis batch ----------------- + { + const NewRollupContractAddr = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) + + const Rollup = await hre.ethers.getContractAt(ContractFactoryName.Rollup, NewRollupContractAddr, deployer) + // import genesis batch + const batchHeader: string = config.batchHeader + + // submitter and challenger + const submitter: string = config.rollupProposer + const challenger: string = config.rollupChallenger + if (!ethers.utils.isAddress(submitter) || !ethers.utils.isAddress(challenger)) { + console.error("please check your address") + return "" + } + let res = await Rollup.importGenesisBatch(batchHeader) + let rec = await res.wait() + console.log( + `importGenesisBatch(%s) ${rec.status == 1 ? "success" : "failed"}`, + batchHeader, + ) + res = await Rollup.addChallenger(challenger) + rec = await res.wait() + console.log(`addChallenger(%s) ${rec.status == 1 ? "success" : "failed"}`, challenger) + const batch = await Rollup.batchBaseStore(0) + assert(batch.batchHash.toLowerCase() != "", `[FATAL] import genesis batch failed`) + } + }) + +task("l1mq-upgrade") + .addParam("storagepath") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + // deploy config + const storagePath = taskArgs.storagepath + const newPath = taskArgs.newpath + + const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle + const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName + ) + const L1CrossDomainMessengerProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1CrossDomainMessengerProxyStorageName + ) + const EnforcedTxGatewayAddress = getContractAddressByName( + storagePath, + ProxyStorageName.EnforcedTxGatewayProxyStorageName + ) + const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) + + // deploy L1MessageQueueWithGasPriceOracle impl + { + const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) + + const Factory = await hre.ethers.getContractFactory(L1MessageQueueWithGasPriceOracleFactoryName) + const contract = await Factory.deploy( + L1CrossDomainMessengerProxyAddress, + NewRollupProxyAddress, + EnforcedTxGatewayAddress + ) + await contract.deployed() + console.log( + "%s=%s ; TX_HASH: %s", + ImplStorageName.L1MessageQueueWithGasPriceOracle, + contract.address.toLocaleLowerCase(), + contract.deployTransaction.hash + ) + const blockNumber = await hre.ethers.provider.getBlockNumber() + console.log("BLOCK_NUMBER: %s", blockNumber) + const err = await storage( + newPath, + ImplStorageName.L1MessageQueueWithGasPriceOracle, + contract.address.toLocaleLowerCase(), + blockNumber || 0 + ) + if (err != "") { + return err + } + } + + // L1MessageQueueWithGasPriceOracle proxy upgrade + { + const L1MessageQueueWithGasPriceOracleNewImplAddress = getContractAddressByName( + newPath, + ImplStorageName.L1MessageQueueWithGasPriceOracle + ) + + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) + const res = await proxyAdmin.upgrade( + L1MessageQueueWithGasPriceOracleProxyAddress, + L1MessageQueueWithGasPriceOracleNewImplAddress + ) + const rec = await res.wait() + console.log(`upgrade l1MessageQueueWithGasPriceOracle.rollup ${rec.status === 1}`) + } + }) + +task("l1cdm-upgrade") + .addParam("storagepath") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + // deploy config + const storagePath = taskArgs.storagepath + const newPath = taskArgs.newpath + + const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger + const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName + const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) + const L1CrossDomainMessengerProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1CrossDomainMessengerProxyStorageName + ) + + // deploy l1CrossDomainMessenger impl + { + const Factory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) + const contract = await Factory.deploy() + await contract.deployed() + console.log( + "%s=%s ; TX_HASH: %s", + L1CrossDomainMessengerImplStorageName, + contract.address.toLocaleLowerCase(), + contract.deployTransaction.hash + ) + const blockNumber = await hre.ethers.provider.getBlockNumber() + console.log("BLOCK_NUMBER: %s", blockNumber) + const err = await storage( + newPath, + L1CrossDomainMessengerImplStorageName, + contract.address.toLocaleLowerCase(), + blockNumber || 0 + ) + if (err != "") { + return err + } + } + + // l1CrossDomainMessenger proxy upgrade + { + const L1CrossDomainMessengerNewImplAddress = getContractAddressByName( + newPath, + L1CrossDomainMessengerImplStorageName + ) + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) + const res = await proxyAdmin.upgrade( + L1CrossDomainMessengerProxyAddress, + L1CrossDomainMessengerNewImplAddress + ) + const rec = await res.wait() + console.log(`upgrade l1CrossDomainMessenger ${rec.status === 1}`) + } + + // l1CrossDomainMessenger update Rollup address + { + const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) + + const L1CDMFactory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) + const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) + const res = await l1CrossDomainMessenger.updateRollup(NewRollupProxyAddress) + const rec = await res.wait() + console.log(`update l1CrossDomainMessenger.rollup ${rec.status === 1}`) + } + }) + + +task("l1staking-deploy-init") + .addParam("storagepath") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + // deploy config + const storagePath = taskArgs.storagepath + const newPath = taskArgs.newpath + const config = hre.deployConfig + const deployer = hre.ethers.provider.getSigner() + + const ProxyFactoryName = ContractFactoryName.DefaultProxy + const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName + const WhitelistImplAddress = getContractAddressByName(storagePath, ImplStorageName.Whitelist) + const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) + const L1CrossDomainMessengerProxyAddress = getContractAddressByName(storagePath, ProxyStorageName.L1CrossDomainMessengerProxyStorageName) + + // deploy L1Staking proxy + { + const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) + // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin + const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") + await proxy.deployed() + const blockNumber = await hre.ethers.provider.getBlockNumber() + const err = await storage(newPath, L1StakingProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) + if (err != "") { + console.log(`deploy L1Staking proxy failed ${err}`) + return err + } + console.log(`L1Staking proxy deploy at ${proxy.address}`) + } + + // deploy impl + { + const Factory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) + const contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) + await contract.deployed() + console.log("%s=%s ; TX_HASH: %s", ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); + await assertContractVariable( + contract, + 'MESSENGER', + L1CrossDomainMessengerProxyAddress + ) + await assertContractVariable( + contract, + 'OTHER_STAKING', + predeploys.L2Staking.toLowerCase() + ) + const blockNumber = await hre.ethers.provider.getBlockNumber() + console.log("BLOCK_NUMBER: %s", blockNumber) + const err = await storage(newPath, ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) + if (err != '') { + console.log(`deploy L1Staking implemention failed ${err}`) + return err + } + } + + // upgrade + { + const RollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) + // Staking config + const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) + const L1StakingImplAddress = getContractAddressByName(newPath, ImplStorageName.L1StakingStorageName) + const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) + const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) + + console.log('Upgrading the Staking proxy...') + const admin: string = config.contractAdmin + const stakingChallengerRewardPercentage: number = config.stakingChallengerRewardPercentage + const limit: number = config.stakingMinDeposit + const lock: number = config.stakingLockNumber + const gasLimitAdd: number = config.stakingCrossChainGaslimitAdd + const gasLimitRemove: number = config.stakingCrossChainGaslimitRemove + + if (!ethers.utils.isAddress(admin) + || lock <= 0 + || limit <= 0 + || gasLimitAdd <= 0 + || gasLimitRemove <= 0 + || stakingChallengerRewardPercentage > 100 + || stakingChallengerRewardPercentage <= 0 + ) { + console.error('please check your address') + return '' + } + + // Upgrade and initialize the proxy. + await IL1StakingProxy.upgradeToAndCall( + L1StakingImplAddress, + L1StakingFactory.interface.encodeFunctionData('initialize', [ + RollupProxyAddress, + hre.ethers.utils.parseEther(limit.toString()), + hre.ethers.utils.parseEther(lock.toString()), + stakingChallengerRewardPercentage, + gasLimitAdd, + gasLimitRemove, + ]) + ) + + await awaitCondition( + async () => { + return ( + (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() + ) + }, + 3000, + 1000 + ) + + const contractTmp = new ethers.Contract( + L1StakingProxyAddress, + L1StakingFactory.interface, + deployer, + ) + + await assertContractVariable( + contractTmp, + 'rollupContract', + RollupProxyAddress + ) + await assertContractVariable( + contractTmp, + 'rewardPercentage', + stakingChallengerRewardPercentage + ) + await assertContractVariable( + contractTmp, + 'stakingValue', + hre.ethers.utils.parseEther(limit.toString()) + ) + await assertContractVariable( + contractTmp, + 'withdrawalLockBlocks', + hre.ethers.utils.parseEther(lock.toString()) + ) + await assertContractVariable( + contractTmp, + 'gasLimitAddStaker', + gasLimitAdd + ) + await assertContractVariable( + contractTmp, + 'gasLimitRemoveStakers', + gasLimitRemove + ) + await assertContractVariable( + contractTmp, + 'owner', + await deployer.getAddress(), + ) + // Wait for the transaction to execute properly. + console.log('StakingProxy upgrade success') + } + + // ------------------ Admin transfer ----------------- + { + const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) + const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() + const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) + const IProxyContract = await hre.ethers.getContractAt( + ContractFactoryName.DefaultProxyInterface, + L1StakingProxyAddress, + deployer + ) + { + const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() + const admin = (await IProxyContract.admin()).toLocaleLowerCase() + if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { + return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` + } + if (admin !== deployerAddr) { + return `Proxy admin address ${admin} should deployer address ${deployerAddr}` + } + } + console.log(`change L1Staking admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) + const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) + await res.wait() + await assertContractVariable( + IProxyContract, + "admin", + ProxyAdminImplAddr, + ProxyAdminImplAddr // caller + ) + console.log(`admin transfer successful`) + } + + // set L1Staking address to gasPriceOracle whitelist + { + const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) + const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) + let addList = [L1StakingProxyAddress] + const res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) + await res.wait() + for (let i = 0; i < addList.length; i++) { + let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) + if (res != true) { + console.error('whitelist check failed') + return '' + } + } + console.log(`add ${addList} to whitelist success`) + } + + // set staker whitelist + { + const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) + const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) + const whiteListAdd = config.l2SequencerAddresses + // set sequencer to white list + await L1Staking.updateWhitelist(whiteListAdd, []) + for (let i = 0; i < config.l2SequencerAddresses.length; i++) { + // Wait for the transaction to execute properly. + await awaitCondition( + async () => { + return ( + await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true + ) + }, + 3000, + 1000 + ) + console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) + } + } + }) + +task("check-params") + .addParam("storagepath") + .addParam("newpath") + .setAction(async (taskArgs, hre) => { + const storagePath = taskArgs.storagepath + const newPath = taskArgs.newpath + + const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName + ) + const L1CrossDomainMessengerProxyAddress = getContractAddressByName( + storagePath, + ProxyStorageName.L1CrossDomainMessengerProxyStorageName + ) + const RollupNewProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) + + const L1CDMFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1CrossDomainMessenger) + const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) + let res = await l1CrossDomainMessenger.rollup() + assert( + RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), + `l1CrossDomainMessenger assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` + ) + + const L1MQFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1MessageQueueWithGasPriceOracle) + const l1mq = L1MQFactory.attach(L1MessageQueueWithGasPriceOracleProxyAddress) + res = await l1mq.ROLLUP_CONTRACT() + assert( + RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), + `l1mq assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` + ) + console.log("Check new rollup address success") + }) + +// test command +// rm -rf ./deployFile.json && \ +// yarn hardhat deploy --storagepath ./deployFile.json --network l1 && \ +// yarn hardhat initialize --storagepath ./deployFile.json --network l1 && \ +// yarn hardhat fund --network l1 && \ +// yarn hardhat register --storagepath ./deployFile.json --network l1 && \ +// rm -rf ./newFile.json && \ +// yarn hardhat rollup-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ +// yarn hardhat l1mq-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ +// yarn hardhat l1cdm-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ +// yarn hardhat check-params --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ +// yarn hardhat l1staking-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ +// yarn hardhat register --storagepath ./newFile.json --network l1 + +// immutable upgrade test +task("impl-test") + .setAction(async (taskArgs, hre) => { + const deployer = hre.ethers.provider.getSigner() + const V1Factory = await hre.ethers.getContractFactory("TestUpgradeV1") + const V2Factory = await hre.ethers.getContractFactory("TestUpgradeV2") + + const v1Impl = await V1Factory.deploy() + await v1Impl.deployed() + const v2Impl = await V2Factory.deploy() + await v2Impl.deployed() + console.log(`V1 and V2 impl deploy success and v1: ${v1Impl.address} , v2: ${v2Impl.address}`) + + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = await ProxyAdminFactory.deploy() + await proxyAdmin.deployed() + const ProxyFactory = await hre.ethers.getContractFactory(ContractFactoryName.DefaultProxy) + const proxy = await ProxyFactory.deploy(v1Impl.address, await deployer.getAddress(), "0x") + await proxy.deployed() + const IProxyContract = await hre.ethers.getContractAt( + ContractFactoryName.DefaultProxyInterface, + proxy.address, + deployer + ) + + // transfer owner to proxy admin + { + const res = await IProxyContract.changeAdmin(proxyAdmin.address) + const rec = await res.wait() + console.log(`proxy admin change to proxy admin ${rec.status === 1}`) + } + + const consoleParams = async (factory) => { + const contractTmp = new ethers.Contract( + proxy.address, + factory.interface, + hre.ethers.provider, + ) + let va = await contractTmp.va({ from: hre.ethers.constants.AddressZero }) + let vb = await contractTmp.vb({ from: hre.ethers.constants.AddressZero }) + let vc = await contractTmp.vc({ from: hre.ethers.constants.AddressZero }) + let version = await contractTmp.version({ from: hre.ethers.constants.AddressZero }) + console.log(`va ${va} ; vb ${vb} ; vc ${vc} ; version ${version}`) + } + let contract = new ethers.Contract( + proxy.address, + V1Factory.interface, + deployer, + ) + let res = await contract.setVersion(100) + let rec = await res.wait() + console.log(`update version to 100 ${rec.status === 1}`) + await consoleParams(V1Factory) + + // upgrade + { + const res = await proxyAdmin.upgrade(proxy.address, v2Impl.address) + const rec = await res.wait() + console.log(`upgrade to v2 impl ${rec.status === 1}`) + } + contract = new ethers.Contract( + proxy.address, + V2Factory.interface, + deployer, + ) + res = await contract.setVersion(101) + rec = await res.wait() + console.log(`update version to 101 ${rec.status === 1}`) + res = await contract.setOtherVersion(99) + rec = await res.wait() + console.log(`update otherVersion to 99 ${rec.status === 1}`) + console.log("upgrade success") + await consoleParams(V2Factory) + }) + +// ------------------------------------ L2 Upgrade ------------------------------------ +task("gov-upgrade") + .addParam("l2config") + .setAction(async (taskArgs, hre) => { + const data = fs.readFileSync(taskArgs.l2config); + // @ts-ignore + const l2Config = JSON.parse(data); + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const GovFactory = await hre.ethers.getContractFactory("Gov") + const newGovImpl = await GovFactory.deploy() + await newGovImpl.deployed() + const res = await proxyAdmin.upgradeAndCall( + predeploys.Gov, + newGovImpl.address, + GovFactory.interface.encodeFunctionData('initializeV2', [ + l2Config.govVotingDuration, + l2Config.govBatchBlockInterval, + l2Config.govBatchMaxBytes, + l2Config.govBatchTimeout, + l2Config.govBatchMaxChunks, + l2Config.govRollupEpoch, + ]) + ) + const rec = await res.wait() + console.log(`gov upgrade ${rec.status === 1}`) + }) + +task("distribute-deploy") + .setAction(async (taskArgs, hre) => { + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const DistributeFactory = await hre.ethers.getContractFactory("Distribute") + const distribute = await DistributeFactory.deploy() + await distribute.deployed() + const res = await proxyAdmin.upgradeAndCall( + predeploys.Distribute, + distribute.address, + DistributeFactory.interface.encodeFunctionData('initialize', []) + ) + const rec = await res.wait() + console.log(`distribute upgrade ${rec.status === 1}, new impl ${distribute.address}`) + }) + +task("morph-token-deploy") + .addParam("l2config") + .setAction(async (taskArgs, hre) => { + const data = fs.readFileSync(taskArgs.l2config); + // @ts-ignore + const l2Config = JSON.parse(data); + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const MorphTokenFactory = await hre.ethers.getContractFactory("MorphToken") + const morphToken = await MorphTokenFactory.deploy() + await morphToken.deployed() + + const res = await proxyAdmin.upgradeAndCall( + predeploys.MorphToken, + morphToken.address, + MorphTokenFactory.interface.encodeFunctionData('initialize', [ + l2Config.morphTokenName, + l2Config.morphTokenSymbol, + l2Config.morphTokenOwner, + hre.ethers.utils.parseEther(l2Config.morphTokenInitialSupply.toString()), + l2Config.morphTokenDailyInflationRate, + ]) + ) + const rec = await res.wait() + console.log(`morphToken upgrade ${rec.status === 1}, new impl ${morphToken.address}`) + }) + +task("sequencer-deploy") + .addParam("l2config") + .setAction(async (taskArgs, hre) => { + const data = fs.readFileSync(taskArgs.l2config); + // @ts-ignore + const l2Config = JSON.parse(data); + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const SequencerFactory = await hre.ethers.getContractFactory("Sequencer") + const sequencer = await SequencerFactory.deploy() + await sequencer.deployed() + + // l2Config + let addresses = [] + for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { + addresses.push(l2Config.l2StakingAddresses[i]) + } + const res = await proxyAdmin.upgradeAndCall( + predeploys.Sequencer, + sequencer.address, + SequencerFactory.interface.encodeFunctionData( + 'initialize', + [addresses]) + ) + const rec = await res.wait() + console.log(`sequencer upgrade ${rec.status === 1}, new impl ${sequencer.address}`) + }) + +task("record-deploy") + .addParam("l2config") + .setAction(async (taskArgs, hre) => { + const data = fs.readFileSync(taskArgs.l2config); + // @ts-ignore + const l2Config = JSON.parse(data); + + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const RecordFactory = await hre.ethers.getContractFactory("Record") + const record = await RecordFactory.deploy() + await record.deployed() + const res = await proxyAdmin.upgradeAndCall( + predeploys.Record, + record.address, + RecordFactory.interface.encodeFunctionData('initialize', [ + l2Config.recordOracleAddress, + l2Config.recordNextBatchSubmissionIndex, + ]) + ) + const rec = await res.wait() + console.log(`Record upgrade ${rec.status === 1}, new impl ${record.address}`) + }) + +task("l2-staking-deploy") + .addParam("newpath") + .addParam("l2config") + .setAction(async (taskArgs, hre) => { + const newPath = taskArgs.newpath + const data = fs.readFileSync(taskArgs.l2config); + // @ts-ignore + const l2Config = JSON.parse(data); + const L1StakingProxyAddr = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) + + const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) + const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) + + const L2StakingFactory = await hre.ethers.getContractFactory("L2Staking") + const staking = await L2StakingFactory.deploy(L1StakingProxyAddr) + await staking.deployed() + + let infos = [] + for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { + let info = { + addr: l2Config.l2StakingAddresses[i], + tmKey: l2Config.l2StakingTmKeys[i], + blsKey: l2Config.l2StakingBlsKeys[i], + } + infos.push(info) + } + const res = await proxyAdmin.upgradeAndCall( + predeploys.L2Staking, + staking.address, + L2StakingFactory.interface.encodeFunctionData('initialize', [ + l2Config.l2StakingSequencerMaxSize, + l2Config.l2StakingUnDelegatedLockEpochs, + l2Config.l2StakingRewardStartTime, + infos, + ]) + ) + const rec = await res.wait() + console.log(`L2Staking upgrade ${rec.status === 1}, new impl ${staking.address}`) + }) \ No newline at end of file diff --git a/gas-oracle/.env.dev b/gas-oracle/.env.dev index f59892b9c..3091dcb34 100644 --- a/gas-oracle/.env.dev +++ b/gas-oracle/.env.dev @@ -13,9 +13,6 @@ TXN_PER_BLOCK = 1 TXN_PER_BATCH = 50 L1_ROLLUP = "0xC5386CBDa4864aE1F86Ed5840D370855F64Bcd3c" -# Sepolia Proxy creation tx 0xe0565450edc796d2ccf37f3c70c119a2db22d44021930bab3375852e36deec90. -# Production deployments must inject the block recorded in their deployment manifest. -GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK = 4239849 L2_GAS_PRICE_ORACLE = "0x5FbDB2315678afecb367f032d93F642f64180aa3" L2_GAS_ORACLE_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" @@ -30,4 +27,4 @@ GAS_ORACLE_EXTERNAL_SIGN_URL = "http://localhost:8080/v1/sign/tx_sign" GAS_ORACLE_L1_BASE_FEE_BUFFER = 0 GAS_ORACLE_L1_BLOB_BASE_FEE_BUFFER = 0 GAS_ORACLE_COMMIT_SCALAR_BUFFER = 0 -GAS_ORACLE_BLOB_SCALAR_BUFFER = 0 +GAS_ORACLE_BLOB_SCALAR_BUFFER = 0 \ No newline at end of file diff --git a/gas-oracle/Makefile b/gas-oracle/Makefile index 05001fb6f..c6ee078a8 100644 --- a/gas-oracle/Makefile +++ b/gas-oracle/Makefile @@ -8,15 +8,15 @@ run:build # Run the formatter but don't change any files. fmt: - cd app && cargo fmt --all -- --check + cd app && cargo +nightly fmt --all -- --check # Run the formatter and update files with style changes lint: - cd app && cargo fmt --all + cd app && cargo +nightly fmt --all # Run clippy clippy: - cd app && cargo clippy --all-targets -- -D warnings + cd app && cargo +nightly clippy --all-targets -- -D warnings # Run all tests test: @@ -37,4 +37,4 @@ help: @echo "test: Run all tests" @echo "clean: Clean the builds" @echo "help: Show this help message" - @echo "" + @echo "" \ No newline at end of file diff --git a/gas-oracle/app/Cargo.lock b/gas-oracle/app/Cargo.lock index c0f49cdb3..2f6cccb68 100644 --- a/gas-oracle/app/Cargo.lock +++ b/gas-oracle/app/Cargo.lock @@ -137,7 +137,6 @@ name = "app" version = "0.1.0" dependencies = [ "axum", - "c-kzg", "dotenv", "env_logger", "ethers", @@ -370,18 +369,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blst" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" -dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", -] - [[package]] name = "brotli" version = "6.0.0" @@ -461,21 +448,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "c-kzg" -version = "2.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" -dependencies = [ - "blst", - "cc", - "glob", - "hex", - "libc", - "once_cell", - "serde", -] - [[package]] name = "camino" version = "1.1.7" @@ -510,14 +482,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.4.0" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ - "find-msvc-tools", "jobserver", "libc", - "shlex", + "once_cell", ] [[package]] @@ -1294,12 +1265,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "find-msvc-tools" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2295,9 +2260,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.4" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "open-fastrlp" @@ -3379,12 +3344,6 @@ dependencies = [ "keccak", ] -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3654,15 +3613,6 @@ dependencies = [ "syn 2.0.66", ] -[[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.36" @@ -4492,20 +4442,6 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] [[package]] name = "zip" diff --git a/gas-oracle/app/Cargo.toml b/gas-oracle/app/Cargo.toml index 29be3eefc..7fbb3b4e1 100644 --- a/gas-oracle/app/Cargo.toml +++ b/gas-oracle/app/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -c-kzg = "=2.1.5" ethers = { version = "2.0", features = ["optimism"] } tokio = { version = "1", features = ["full"] } dotenv = "0.15.0" diff --git a/gas-oracle/app/rust-toolchain b/gas-oracle/app/rust-toolchain index 6979a6c06..f1d81c421 100644 --- a/gas-oracle/app/rust-toolchain +++ b/gas-oracle/app/rust-toolchain @@ -1 +1 @@ -1.91.0 +nightly-2023-12-03 \ No newline at end of file diff --git a/gas-oracle/app/rustfmt.toml b/gas-oracle/app/rustfmt.toml index 057dc57df..68c3c9303 100644 --- a/gas-oracle/app/rustfmt.toml +++ b/gas-oracle/app/rustfmt.toml @@ -1,3 +1,11 @@ reorder_imports = true +imports_granularity = "Crate" use_small_heuristics = "Max" +comment_width = 100 +wrap_comments = true +binop_separator = "Back" +trailing_comma = "Vertical" +trailing_semicolon = false use_field_init_shorthand = true +format_code_in_doc_comments = true +doc_comment_code_block_width = 100 diff --git a/gas-oracle/app/src/abi/Rollup.json b/gas-oracle/app/src/abi/Rollup.json index e9da0e250..28f7a5c6d 100644 --- a/gas-oracle/app/src/abi/Rollup.json +++ b/gas-oracle/app/src/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -325,25 +306,6 @@ "name": "UpdateProofWindow", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +364,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +441,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,121 +637,33 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ + }, { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "signature", "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" } ], - "name": "commitState", + "name": "commitBatch", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -924,7 +779,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -971,32 +826,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +864,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1100,25 +942,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "pendingBatchCount", - "outputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proofRewardPercent", @@ -1145,24 +968,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proveRemaining", @@ -1245,19 +1050,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1271,19 +1063,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1336,19 +1115,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/gas-oracle/app/src/abi/mod.rs b/gas-oracle/app/src/abi/mod.rs index 2db3287a1..fdcc9a2c2 100644 --- a/gas-oracle/app/src/abi/mod.rs +++ b/gas-oracle/app/src/abi/mod.rs @@ -13,8 +13,3 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } - -pub mod pre_submitter_rollup_abi { - use ethers::prelude::abigen; - abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); -} diff --git a/gas-oracle/app/src/abi/pre_submitter/Rollup.json b/gas-oracle/app/src/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/gas-oracle/app/src/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/gas-oracle/app/src/da_scalar/blob.rs b/gas-oracle/app/src/da_scalar/blob.rs index 4320cbbef..dea157f3c 100644 --- a/gas-oracle/app/src/da_scalar/blob.rs +++ b/gas-oracle/app/src/da_scalar/blob.rs @@ -77,7 +77,7 @@ impl Blob { let max_payload_size = num_blobs * (MAX_BLOB_TX_PAYLOAD_SIZE - 4096); if compressed_len as usize > max_payload_size { - return Err(BlobError::Error(anyhow!("oversized batch payload"))); + return Err(BlobError::Error(anyhow!("oversized batch payload"))) } let compressed_batch = decoded_blob[..compressed_len].to_vec(); @@ -103,7 +103,7 @@ impl Blob { if origin_batch.len() != orgin_content_size as usize { return Err(BlobError::Error(anyhow!( "decompress batch error: origin_batch_len is not equal to zstd_orgin_content_size" - ))); + ))) } let total_blob_payload = num_blobs as f32 * (MAX_BLOB_TX_PAYLOAD_SIZE - 4096) as f32; @@ -163,8 +163,8 @@ fn parse_block_header( // resolve Block_Size (21 bits) let block_size = - ((header[0] as u32 >> 3) | ((header[1] as u32) << 5) | ((header[2] as u32) << 13)) - & 0x1FFFFF; + ((header[0] as u32 >> 3) | ((header[1] as u32) << 5) | ((header[2] as u32) << 13)) & + 0x1FFFFF; Ok((last_block, block_type, block_size)) } diff --git a/gas-oracle/app/src/da_scalar/blob_client.rs b/gas-oracle/app/src/da_scalar/blob_client.rs index 266a08659..8a2f2871b 100644 --- a/gas-oracle/app/src/da_scalar/blob_client.rs +++ b/gas-oracle/app/src/da_scalar/blob_client.rs @@ -26,10 +26,10 @@ impl BeaconNode { indexes: Vec, ) -> Result { let client = reqwest::blocking::Client::new(); - let mut url = l1_beacon_rpc.to_owned() - + "/eth/v1/beacon/blob_sidecars/" - + slot.to_string().as_str() - + "?"; + let mut url = l1_beacon_rpc.to_owned() + + "/eth/v1/beacon/blob_sidecars/" + + slot.to_string().as_str() + + "?"; for index in indexes { url = url + "indices=" + index.to_string().as_str() + "&"; } diff --git a/gas-oracle/app/src/da_scalar/calculate.rs b/gas-oracle/app/src/da_scalar/calculate.rs index b67251129..7e7df970a 100644 --- a/gas-oracle/app/src/da_scalar/calculate.rs +++ b/gas-oracle/app/src/da_scalar/calculate.rs @@ -1,108 +1,18 @@ -use std::collections::BTreeMap; - -use c_kzg::{ethereum_kzg_settings, Blob as KzgBlob, Bytes48}; use ethers::{ prelude::*, utils::{hex, rlp}, }; use eyre::anyhow; +use serde::{Deserialize, Serialize}; use serde_json::Value; use super::{ - blob::{decompress_batch, kzg_to_versioned_hash, Blob as MorphBlob}, + blob::{decompress_batch, kzg_to_versioned_hash, Blob}, error::ScalarError, typed_tx::TypedTransaction, MAX_BLOB_TX_PAYLOAD_SIZE, }; -fn sidecar_index(sidecar: &Value) -> Result { - let raw = sidecar.get("index").and_then(Value::as_str).ok_or_else(|| { - ScalarError::CalculateError(anyhow!("beacon blob sidecar index is missing or not a string")) - })?; - if raw.is_empty() || !raw.bytes().all(|byte| byte.is_ascii_digit()) { - return Err(ScalarError::CalculateError(anyhow!( - "beacon blob sidecar index is not an unsigned decimal integer" - ))); - } - raw.parse::().map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar index overflows u64: {e}" - ))) - }) -} - -fn decode_beacon_hex( - sidecar: &Value, - field: &'static str, - expected_len: usize, -) -> Result, ScalarError> { - let encoded = sidecar.get(field).and_then(Value::as_str).ok_or_else(|| { - ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar {field} is missing or not a string" - ))) - })?; - let payload = encoded.strip_prefix("0x").ok_or_else(|| { - ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar {field} must be 0x-prefixed" - ))) - })?; - if payload.len() != expected_len.saturating_mul(2) { - return Err(ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar {field} has invalid encoded length" - )))); - } - let decoded = hex::decode(payload).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar {field} is not valid hex: {e}" - ))) - })?; - if decoded.len() != expected_len { - return Err(ScalarError::CalculateError(anyhow!(format!( - "beacon blob sidecar {field} has invalid decoded length" - )))); - } - Ok(decoded) -} - -fn verify_blob_sidecar( - sidecar: &Value, - expected_versioned_hash: H256, -) -> Result<[u8; MAX_BLOB_TX_PAYLOAD_SIZE], ScalarError> { - let commitment_bytes = decode_beacon_hex(sidecar, "kzg_commitment", 48)?; - let actual_versioned_hash = kzg_to_versioned_hash(&commitment_bytes); - if expected_versioned_hash != actual_versioned_hash { - return Err(ScalarError::CalculateError(anyhow!(format!( - "invalid blob versioned hash: expected {expected_versioned_hash:?}, got {actual_versioned_hash:?}" - )))); - } - - let blob_bytes = decode_beacon_hex(sidecar, "blob", MAX_BLOB_TX_PAYLOAD_SIZE)?; - let proof_bytes = decode_beacon_hex(sidecar, "kzg_proof", 48)?; - let blob = KzgBlob::from_bytes(&blob_bytes).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!("invalid KZG blob encoding: {e}"))) - })?; - let commitment = Bytes48::from_bytes(&commitment_bytes).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!("invalid KZG commitment encoding: {e}"))) - })?; - let proof = Bytes48::from_bytes(&proof_bytes).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!("invalid KZG proof encoding: {e}"))) - })?; - let verified = ethereum_kzg_settings(0) - .verify_blob_kzg_proof(&blob, &commitment, &proof) - .map_err(|e| { - ScalarError::CalculateError(anyhow!(format!("KZG sidecar verification failed: {e}"))) - })?; - if !verified { - return Err(ScalarError::CalculateError(anyhow!( - "KZG sidecar proof does not match blob and commitment" - ))); - } - - blob_bytes.try_into().map_err(|_| { - ScalarError::CalculateError(anyhow!("verified blob has an unexpected byte length")) - }) -} - /// Extract the full batch data from multiple blobs. /// All blobs belong to the same batch: the batch is compressed as a whole, split into /// multiple segments (each at most 4096 * 31 bytes), and then encoded into BLS12-381 @@ -113,46 +23,76 @@ pub(super) fn extract_tx_payload( sidecars: &[Value], ) -> Result, ScalarError> { let num_blobs = indexed_hashes.len(); - let mut sidecars_by_index = BTreeMap::new(); - for sidecar in sidecars { - let index = sidecar_index(sidecar)?; - if sidecars_by_index.insert(index, sidecar).is_some() { - return Err(ScalarError::CalculateError(anyhow!(format!( - "beacon response contains duplicate blob sidecar index {index}" - )))); - } - } - let mut combined_payload = Vec::::new(); for i_h in indexed_hashes { - let sidecar = sidecars_by_index.get(&i_h.index).ok_or_else(|| { - ScalarError::CalculateError(anyhow!(format!( + if let Some(sidecar) = sidecars.iter().find(|sidecar| { + sidecar["index"].as_str().unwrap_or("1000").parse::().unwrap_or(1000) == i_h.index + }) { + let kzg_commitment = sidecar["kzg_commitment"].as_str().ok_or_else(|| { + ScalarError::CalculateError(anyhow!("Failed to fetch kzg commitment from blob")) + })?; + let decoded_commitment: Vec = + hex::decode(kzg_commitment).map_err(|e| ScalarError::CalculateError(e.into()))?; + let actual_versioned_hash = kzg_to_versioned_hash(&decoded_commitment); + + if i_h.hash != actual_versioned_hash { + log::error!( + "expected hash {:?} for blob at index {:?} but got {:?}", + i_h.hash, + i_h.index, + actual_versioned_hash + ); + + return Err(ScalarError::CalculateError(anyhow!(format!( + "Invalid versionedHash for Blob, expected hash {:?} for blob at index {:?} but got {:?}", + i_h.hash, i_h.index, actual_versioned_hash + )))); + } + + let encoded_blob = sidecar["blob"].as_str().ok_or_else(|| { + ScalarError::CalculateError(anyhow!(format!( + "Missing blob value in blob_hash: {:?}", + i_h.hash + ))) + })?; + let decoded_blob = hex::decode(encoded_blob).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "Failed to decode blob, blob_hash: {:?}, err: {}", + i_h.hash, e + ))) + })?; + + if decoded_blob.len() != MAX_BLOB_TX_PAYLOAD_SIZE { + return Err(ScalarError::CalculateError(anyhow!("Invalid length for Blob"))); + } + + let blob_array: [u8; MAX_BLOB_TX_PAYLOAD_SIZE] = decoded_blob.try_into().unwrap(); + let blob_struct = Blob(blob_array); + // Extract the raw payload segment by removing only the BLS12-381 encoding, + // without zstd decompression. + let payload_bytes = blob_struct.get_payload_bytes().map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "Failed to get payload bytes from blob, blob_hash: {:?}, err: {}", + i_h.hash, e + ))) + })?; + combined_payload.extend_from_slice(&payload_bytes); + } else { + return Err(ScalarError::CalculateError(anyhow!(format!( "no blob in response matches desired index: {}", i_h.index - ))) - })?; - let blob_array = verify_blob_sidecar(sidecar, i_h.hash)?; - let blob_struct = MorphBlob(blob_array); - // Extract the raw payload segment by removing only the BLS12-381 encoding, - // without zstd decompression. - let payload_bytes = blob_struct.get_payload_bytes().map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "Failed to get payload bytes from blob, blob_hash: {:?}, err: {}", - i_h.hash, e - ))) - })?; - combined_payload.extend_from_slice(&payload_bytes); + )))); + } } // After concatenation, use detect_zstd_compressed to trim the valid compressed payload // (excluding trailing zero padding), then decompress the batch as a whole. - let compressed_data = - MorphBlob::detect_zstd_compressed(combined_payload, num_blobs).map_err(|e| { - ScalarError::CalculateError(anyhow!(format!( - "Failed to detect zstd compressed data from combined blob payload: {}", - e - ))) - })?; + let compressed_data = Blob::detect_zstd_compressed(combined_payload, num_blobs).map_err(|e| { + ScalarError::CalculateError(anyhow!(format!( + "Failed to detect zstd compressed data from combined blob payload: {}", + e + ))) + })?; decompress_batch(&compressed_data).map_err(|e| { ScalarError::CalculateError(anyhow!(format!( "Failed to decompress combined blob payload: {}", @@ -161,20 +101,18 @@ pub(super) fn extract_tx_payload( }) } -pub fn extract_txn_count(origin_batch: &[u8], last_block_num: u64) -> Option { +pub fn extract_txn_count(origin_batch: &Vec, last_block_num: u64) -> Option { if origin_batch.is_empty() || origin_batch.len() < 8 { return None; } let first_block_num = u64::from_be_bytes(origin_batch[0..8].try_into().unwrap_or_default()); - let block_count = last_block_num.checked_sub(first_block_num)?.checked_add(1)?; - let block_count = usize::try_from(block_count).ok()?; - let required_len = 60usize.checked_mul(block_count)?; - if origin_batch.len() < required_len { + let block_count = last_block_num - first_block_num + 1; + if origin_batch.len() < 60 * block_count as usize { log::error!("invalid blob batch len"); return None; } let mut txn_count_in_batch = 0u64; - for i in 0..block_count { + for i in 0..block_count as usize { let bys = &origin_batch[60 * i + 56..60 * i + 58]; let num_txn = u16::from_be_bytes(bys.try_into().unwrap_or_default()); @@ -191,40 +129,13 @@ pub fn extract_txn_count(origin_batch: &[u8], last_block_num: u64) -> Option, -} - -type HistoricalCommitIndex = HashMap>; - -fn index_commit_logs(logs: Vec) -> HistoricalCommitIndex { - let mut index = HistoricalCommitIndex::new(); - for log in logs { - if log.removed.unwrap_or_default() { - continue; - } - let Some(topic) = log.topics.get(1) else { - continue; - }; - let batch_index = U256::from_big_endian(topic.as_bytes()); - if batch_index > U256::from(u64::MAX) { - continue; - } - index.entry(batch_index.as_u64()).or_default().push(log); - } - index -} - -fn batch_indices_from_commit_logs(logs: &[Log], max_batch_index: u64) -> BTreeSet { - logs.iter() - .filter(|log| !log.removed.unwrap_or_default()) - .filter_map(|log| log.topics.get(1)) - .filter_map(|topic| { - let value = U256::from_big_endian(topic.as_bytes()); - (value <= U256::from(max_batch_index)).then(|| value.as_u64()) - }) - .filter(|index| *index > 0) - .collect() -} - -fn ensure_snapshot_hash(expected: H256, actual: Option) -> Result<(), ScalarError> { - if actual != Some(expected) { - return Err(ScalarError::Error(anyhow!( - "finalized snapshot hash changed; discard the complete DA sample round" - ))); - } - Ok(()) -} - -fn transaction_blob_hashes(transaction: &Transaction) -> Vec { - transaction - .other - .get_with("blobVersionedHashes", serde_json::from_value::>) - .unwrap_or(Ok(Vec::new())) - .unwrap_or_default() -} - -fn receipt_matches_source(receipt: &TransactionReceipt, source: &BlobSource) -> bool { - receipt.transaction_hash == source.transaction_hash - && receipt.block_number == Some(source.block_number) - && receipt.block_hash == Some(source.block_hash) - && receipt.transaction_index == source.transaction_index -} - -fn blob_commitment(version: u8, hashes: &[H256]) -> Result { - match version { - 0 | 1 if hashes.len() == 1 => Ok(hashes[0]), - 0 | 1 => Err(ScalarError::Error(anyhow!(format!( - "legacy batch must have exactly one blob, got {}", - hashes.len() - )))), - 2 if !hashes.is_empty() => { - let bytes: Vec = - hashes.iter().flat_map(|hash| hash.as_bytes().iter().copied()).collect(); - Ok(H256::from(keccak256(bytes))) - } - 2 => Err(ScalarError::Error(anyhow!("V2 batch has no blob"))), - _ => Err(ScalarError::Error(anyhow!(format!("unsupported batch version {version}")))), - } -} - -fn validate_fresh_blob_commitment( - stored_commitment: H256, - transaction_commitment: H256, -) -> Result<(), ScalarError> { - // Rollup garbage-collects the mapping after successor finalization. A - // direct canonical blob transaction remains a stable source even when the - // snapshot getter has already returned zero. - if !stored_commitment.is_zero() && stored_commitment != transaction_commitment { - return Err(ScalarError::Error(anyhow!(format!( - "canonical blob commitment mismatch: stored={stored_commitment:?}, tx={transaction_commitment:?}" - )))); - } - Ok(()) -} - -fn recover_gc_commitment(snapshot: H256, canonical_block: H256) -> H256 { - if snapshot.is_zero() { - canonical_block - } else { - snapshot - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum BloblessDisposition { - ExcludeMissing, - ExcludeZero, - ResolveStored(H256), -} - -fn classify_blobless_submission( - version: u8, - kind: SubmissionKind, - pre_submitter: bool, - stored_commitment: H256, -) -> Result { - if kind == SubmissionKind::CommitBatch && !pre_submitter { - return Err(ScalarError::Error(anyhow!( - "current canonical commitBatch has no blob; refusing zero-data scalar sample" - ))); - } - - if version <= 1 && stored_commitment == ZERO_VERSIONED_HASH { - // Before the Submitter cutover, commitBatch legitimately accepted a - // V0/V1 transaction without a blob and stored ZERO_VERSIONED_HASH. - // Permissionless proof/state submissions can also reuse that value. - return Ok(BloblessDisposition::ExcludeZero); - } - if stored_commitment.is_zero() { - return Ok(BloblessDisposition::ExcludeMissing); - } - if kind == SubmissionKind::CommitBatch { - return Err(ScalarError::Error(anyhow!( - "legacy canonical commitBatch is blobless with a non-zero stored commitment" - ))); - } - Ok(BloblessDisposition::ResolveStored(stored_commitment)) -} // Main struct to manage overhead information pub struct ScalarUpdater { @@ -184,7 +33,6 @@ pub struct ScalarUpdater { ext_signer: Option, l1_rollup: Rollup>, // Rollup object for L1 beacon_node: BeaconNode, // Beacon node for blockchain - l1_rollup_deploy_block: u64, gas_threshold: u64, commit_scalar_buffer: u64, blob_scalar_buffer: u64, @@ -202,7 +50,6 @@ impl ScalarUpdater { ext_signer: Option, l1_rollup: Rollup>, l1_beacon_rpc: String, - l1_rollup_deploy_block: u64, gas_threshold: u64, commit_scalar_buffer: u64, blob_scalar_buffer: u64, @@ -220,7 +67,6 @@ impl ScalarUpdater { ext_signer, l1_rollup, beacon_node, - l1_rollup_deploy_block, gas_threshold, commit_scalar_buffer, blob_scalar_buffer, @@ -233,47 +79,27 @@ impl ScalarUpdater { /// Calculate the user's average cost of the latest rollup and set it to the GasPriceOrale /// contract on the L2 network. pub async fn update(&mut self) -> Result<(), ScalarError> { - // Step1. Pin all reads to one finalized L1 block. A latest-head sample - // can be reorged after the oracle has already written its L2 scalar. - let snapshot = self - .l1_provider - .get_block(BlockNumber::Finalized) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "overhead.l1_provider.get finalized block error: {:#?}", - e - ))) - })? - .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block is unavailable")))?; - let snapshot_number = snapshot - .number - .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block has no number")))?; - let snapshot_hash = snapshot - .hash - .ok_or_else(|| ScalarError::Error(anyhow!("finalized L1 block has no hash")))?; - if self.l1_rollup_deploy_block == 0 - || self.l1_rollup_deploy_block > snapshot_number.as_u64() - { - return Err(ScalarError::Error(anyhow!(format!( - "configured Rollup deployment block {} is outside finalized snapshot 1..={}", - self.l1_rollup_deploy_block, snapshot_number - )))); - } - let start = if snapshot_number > U64::from(SAMPLE_LOOKBACK_BLOCKS) { - snapshot_number - U64::from(SAMPLE_LOOKBACK_BLOCKS) + // Step1. fetch latest batches and calculate scalar. + let latest = self.l1_provider.get_block_number().await.map_err(|e| { + ScalarError::Error(anyhow!(format!( + "overhead.l1_provider.get_block_number error: {:#?}", + e + ))) + })?; + let start = if latest > U64::from(100) { + latest - U64::from(100) //100 } else { U64::from(1) }; - let (mut commit_scalar, mut blob_scalar) = - match self.calculate_scalar(start.as_u64(), snapshot_number, snapshot_hash).await { - Ok(Some(scalar)) => scalar, - Ok(None) => { - return Ok(()); - } - Err(e) => return Err(e), - }; + let (mut commit_scalar, mut blob_scalar) = match self.calculate_scalar(start.as_u64()).await + { + Ok(Some(scalar)) => scalar, + Ok(None) => { + return Ok(()); + } + Err(e) => return Err(e), + }; // Step2. fetch current scalar on l2. let current_commit_scalar: U256 = self.l2_oracle.commit_scalar().await.map_err(|e| { @@ -344,491 +170,84 @@ impl ScalarUpdater { need_update } - async fn calculate_scalar( - &mut self, - start: u64, - snapshot_number: U64, - snapshot_hash: H256, - ) -> Result, ScalarError> { - let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); - let last_batch_index = self + async fn calculate_scalar(&mut self, start: u64) -> Result, ScalarError> { + let filter = self .l1_rollup - .last_committed_batch_index() - .block(block_id) - .call() - .await - .map_err(|e| ScalarError::Error(anyhow!(format!("query last committed batch: {e:?}"))))? - .as_u64(); - if last_batch_index == 0 { - log::warn!("no non-genesis batch exists at finalized L1 snapshot, skip update"); - return Ok(None); - } - - let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); - let candidate_logs = self - .l1_provider - .get_logs( - &Filter::new() - .address(self.l1_rollup.address()) - .from_block(start) - .to_block(snapshot_number) - .topic0(commit_topic), - ) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!("query finalized Commit window: {e:?}"))) - })?; - let batch_indices = batch_indices_from_commit_logs(&candidate_logs, last_batch_index); - if batch_indices.is_empty() { - log::warn!("no Commit event exists in the finalized DA sample window"); - return Ok(None); - } - - let mut seen_sources = HashSet::new(); - let mut commit_scalar_sum = 0u128; - let mut blob_scalar_sum = 0u128; - let mut sample_count = 0u128; - let mut historical_commits = None; - - for batch_index in batch_indices { - let canonical = resolve_canonical_commit( - &self.l1_rollup, - &self.l1_provider, - batch_index, - start, - snapshot_number, - ) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "resolve canonical commit for batch {batch_index}: {e:#}" - ))) - })?; - let Some(canonical) = canonical else { - // The window may contain a Commit that was canonically reverted - // before the pinned snapshot. It contributes no DA sample. - continue; - }; + .commit_batch_filter() + .filter + .from_block(start) + .address(self.l1_rollup.address()); - let canonical_tx = self.load_commit_transaction(canonical).await?; - let input = decode_batch_data_input(canonical_tx.input.as_ref()).map_err(|e| { - ScalarError::Error(anyhow!(format!( - "decode canonical commit {:?}: {e:#}", - canonical.transaction_hash - ))) - })?; - let blob_source = self - .resolve_blob_source( - batch_index, - canonical, - &canonical_tx, - input.version, - input.kind, - input.pre_submitter, - snapshot_number, - snapshot_hash, - &mut historical_commits, - ) - .await?; - let Some(blob_source) = blob_source else { - ORACLE_SERVICE_METRICS.da_sample_exclusions.inc(); - log::warn!( - "canonical batch {} has no verifiable real DA blob source; excluded", - batch_index - ); - continue; - }; - if !seen_sources.insert(blob_source.clone()) { - ORACLE_SERVICE_METRICS.da_sample_exclusions.inc(); - log::warn!( - "duplicate DA blob source {:?} in finalized window; counted once", - blob_source.transaction_hash - ); - continue; - } + let mut logs = self.l1_provider.get_logs(&filter).await.map_err(|e| { + ScalarError::Error(anyhow!(format!("overhead.l1_provider.get_logs error: {:#?}", e))) + })?; - let (commit_scalar, blob_scalar) = self - .calculate_from_rollup(blob_source, input.last_block_number) - .await - .inspect_err(|_| { - log::info!( - "scalar is unavailable, canonical_tx_hash ={:#?}", - canonical.transaction_hash - ); - })?; - commit_scalar_sum += u128::from(commit_scalar); - blob_scalar_sum += u128::from(blob_scalar); - sample_count += 1; - } + log::debug!("overhead.l1_provider.submit_batches.get_logs.len ={:#?}", logs.len()); - let after = self - .l1_provider - .get_block(snapshot_number) - .await - .map_err(|e| ScalarError::Error(anyhow!(format!("recheck finalized snapshot: {e:?}"))))? - .ok_or_else(|| ScalarError::Error(anyhow!("finalized snapshot disappeared")))?; - ensure_snapshot_hash(snapshot_hash, after.hash)?; - if sample_count == 0 { + logs.retain(|x| x.transaction_hash.is_some() && x.block_number.is_some()); + if logs.is_empty() { + log::warn!("rollup logs for the last 100 blocks of l1 is empty, skip update"); return Ok(None); } - let commit_scalar = u64::try_from(commit_scalar_sum / sample_count) - .map_err(|_| ScalarError::Error(anyhow!("averaged commit scalar overflow")))?; - let blob_scalar = u64::try_from(blob_scalar_sum / sample_count) - .map_err(|_| ScalarError::Error(anyhow!("averaged blob scalar overflow")))?; - Ok(Some((commit_scalar, blob_scalar))) - } - - async fn load_commit_transaction( - &self, - commit: CanonicalCommit, - ) -> Result { - let transaction = self - .l1_provider - .get_transaction(commit.transaction_hash) - .await - .map_err(|e| ScalarError::Error(anyhow!(format!("get commit transaction: {e:?}"))))? - .ok_or_else(|| { - ScalarError::Error(anyhow!(format!( - "commit transaction {:?} is unavailable", - commit.transaction_hash - ))) - })?; - if transaction.to != Some(self.l1_rollup.address()) - || transaction.block_number != Some(commit.identity.block_number.into()) - || transaction.block_hash != Some(commit.block_hash) - || transaction.transaction_index != Some(commit.identity.transaction_index.into()) - { - return Err(ScalarError::Error(anyhow!(format!( - "commit transaction {:?} moved to a different block", - commit.transaction_hash - )))); - } - Ok(transaction) - } - - async fn load_canonical_block_commitment( - &self, - batch_index: u64, - canonical: CanonicalCommit, - ) -> Result { - if canonical.identity.block_number < self.l1_rollup_deploy_block { - return Err(ScalarError::Error(anyhow!(format!( - "canonical commit block {} predates configured Rollup deployment block {}", - canonical.identity.block_number, self.l1_rollup_deploy_block - )))); - } - - let canonical_number = U64::from(canonical.identity.block_number); - let before = self - .l1_provider - .get_block(BlockNumber::Number(canonical_number)) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "load canonical commit block before historical getter: {e:?}" - ))) - })? - .ok_or_else(|| ScalarError::Error(anyhow!("canonical commit block disappeared")))?; - if before.hash != Some(canonical.block_hash) { - return Err(ScalarError::Error(anyhow!( - "canonical commit block hash changed before historical getter" - ))); - } - - // Use the block hash, rather than an unpinned number, for the historical - // eth_call. This recovers the mapping value before later finalization GC. - let commitment: H256 = self - .l1_rollup - .batch_blob_versioned_hashes(U256::from(batch_index)) - .block(BlockId::Hash(canonical.block_hash)) - .call() - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "query stored blob commitment at canonical commit block: {e:?}" - ))) - })? - .into(); - - let after = self - .l1_provider - .get_block(BlockNumber::Number(canonical_number)) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "recheck canonical commit block after historical getter: {e:?}" - ))) - })? - .ok_or_else(|| ScalarError::Error(anyhow!("canonical commit block disappeared")))?; - if after.hash != Some(canonical.block_hash) { - return Err(ScalarError::Error(anyhow!( - "canonical commit block hash changed during historical getter" - ))); - } - Ok(commitment) - } - - async fn load_historical_commit_index( - &self, - snapshot_number: U64, - ) -> Result { - if self.l1_rollup_deploy_block > snapshot_number.as_u64() { - return Err(ScalarError::Error(anyhow!( - "Rollup deployment block is newer than the finalized snapshot" - ))); - } - - // Replay CommitBatch once per scalar round and share the resulting - // index between every stored-source batch. Replaying the entire chain - // separately for each batch multiplies RPC load by the sample count. - let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); - let mut logs = Vec::new(); - let mut from = self.l1_rollup_deploy_block; - let snapshot = snapshot_number.as_u64(); - loop { - let to = from.saturating_add(LOG_QUERY_RANGE - 1).min(snapshot); - logs.extend( - self.l1_provider - .get_logs( - &Filter::new() - .address(self.l1_rollup.address()) - .from_block(from) - .to_block(to) - .topic0(commit_topic), - ) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!( - "query historical blob-source commits in {from}..={to}: {e:?}" - ))) - })?, - ); - if to == snapshot { - break; - } - from = to - .checked_add(1) - .ok_or_else(|| ScalarError::Error(anyhow!("commit replay block overflow")))?; - } - Ok(index_commit_logs(logs)) - } + let log = logs.iter().max_by_key(|log| log.block_number.unwrap()).ok_or_else(|| { + ScalarError::Error(anyhow!(format!( + "no submit batches logs, start blocknum ={:#?}", + start + ))) + })?; - #[allow(clippy::too_many_arguments)] - async fn resolve_blob_source( - &self, - batch_index: u64, - canonical: CanonicalCommit, - canonical_tx: &Transaction, - version: u8, - kind: SubmissionKind, - pre_submitter: bool, - snapshot_number: U64, - snapshot_hash: H256, - historical_commits: &mut Option, - ) -> Result, ScalarError> { - let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); - let snapshot_commitment: H256 = self - .l1_rollup - .batch_blob_versioned_hashes(U256::from(batch_index)) - .block(block_id) - .call() + #[allow(clippy::manual_inspect)] + let (commit_scalar, blob_scalar) = self + .calculate_from_rollup(log.transaction_hash.unwrap(), log.block_number.unwrap()) .await .map_err(|e| { - ScalarError::Error(anyhow!(format!("query stored blob commitment: {e:?}"))) - })? - .into(); - - let current_hashes = transaction_blob_hashes(canonical_tx); - if !current_hashes.is_empty() { - let actual_commitment = blob_commitment(version, ¤t_hashes)?; - validate_fresh_blob_commitment(snapshot_commitment, actual_commitment)?; - return Ok(Some(BlobSource { - transaction_hash: canonical.transaction_hash, - block_number: canonical.identity.block_number.into(), - block_hash: canonical.block_hash, - transaction_index: canonical.identity.transaction_index.into(), - blob_hashes: current_hashes, - })); - } - - // A post-cutover commitBatch is required by the Rollup contract to - // carry a blob. Keep that invariant fail-closed even if storage was GC'd. - if kind == SubmissionKind::CommitBatch && !pre_submitter { - return classify_blobless_submission(version, kind, pre_submitter, snapshot_commitment) - .map(|_| None); - } - - let canonical_block_commitment = if snapshot_commitment.is_zero() { - self.load_canonical_block_commitment(batch_index, canonical).await? - } else { - snapshot_commitment - }; - let expected_commitment = - recover_gc_commitment(snapshot_commitment, canonical_block_commitment); - match classify_blobless_submission(version, kind, pre_submitter, expected_commitment)? { - BloblessDisposition::ExcludeZero => { - log::warn!( - "canonical batch {} is a legal V0/V1 blobless ZERO_VERSIONED_HASH submission; excluded from DA scalar sampling", - batch_index - ); - return Ok(None); - } - BloblessDisposition::ExcludeMissing => { - log::warn!( - "batch {} stored blob commitment is zero at both finalized snapshot and canonical commit block; excluded and alert", - batch_index + log::info!( + "scalar is none, skip update, tx_hash ={:#?}", + log.transaction_hash.unwrap() ); - return Ok(None); - } - BloblessDisposition::ResolveStored(commitment) => { - debug_assert_eq!(commitment, expected_commitment); - } - } - - // Stored-source recommits intentionally look *before* the last Revert. - // Canonical filtering here would discard the original blob transaction. - if historical_commits.is_none() { - *historical_commits = Some(self.load_historical_commit_index(snapshot_number).await?); - } - let mut candidates = historical_commits - .as_ref() - .and_then(|index| index.get(&batch_index)) - .cloned() - .unwrap_or_default(); - candidates.retain(|log| { - log.block_number - .is_some_and(|number| number.as_u64() <= canonical.identity.block_number) - }); - candidates.sort_by_key(|log| { - ( - log.block_number.unwrap_or_default(), - log.transaction_index.unwrap_or_default(), - log.log_index.unwrap_or_default(), - ) - }); - - for candidate in candidates.into_iter().rev() { - let Some(transaction_hash) = candidate.transaction_hash else { - continue; - }; - if transaction_hash == canonical.transaction_hash { - continue; - } - let Some(block_number) = candidate.block_number else { - continue; - }; - let Some(block_hash) = candidate.block_hash else { - continue; - }; - let Some(transaction_index) = candidate.transaction_index else { - continue; - }; - let Some(transaction) = - self.l1_provider.get_transaction(transaction_hash).await.map_err(|e| { - ScalarError::Error(anyhow!(format!("get blob-source transaction: {e:?}"))) - })? - else { - continue; - }; - if transaction.to != Some(self.l1_rollup.address()) - || transaction.block_number != Some(block_number) - || transaction.block_hash != Some(block_hash) - || transaction.transaction_index != Some(transaction_index) - { - return Err(ScalarError::Error(anyhow!(format!( - "blob-source transaction {transaction_hash:?} changed block identity" - )))); - } - let Ok(candidate_input) = decode_batch_data_input(transaction.input.as_ref()) else { - continue; - }; - if candidate_input.version != version { - continue; - } - let hashes = transaction_blob_hashes(&transaction); - if hashes.is_empty() { - continue; - } - if blob_commitment(candidate_input.version, &hashes)? != expected_commitment { - continue; - } - - let after = self - .l1_provider - .get_block(snapshot_number) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!("recheck finalized snapshot: {e:?}"))) - })? - .ok_or_else(|| ScalarError::Error(anyhow!("finalized snapshot disappeared")))?; - ensure_snapshot_hash(snapshot_hash, after.hash)?; - log::info!( - "resolved stored blob source: batch={}, canonical_tx={:?}, source_tx={:?}, source_block={}, blobs={}", - batch_index, - canonical.transaction_hash, - transaction_hash, - block_number, - hashes.len() - ); - return Ok(Some(BlobSource { - transaction_hash, - block_number, - block_hash, - transaction_index, - blob_hashes: hashes, - })); - } + e + })?; - log::warn!( - "no historical blob source matches batch {} commitment {:?}; exclude and alert", - batch_index, - expected_commitment - ); - Ok(None) + Ok(Some((commit_scalar, blob_scalar))) } async fn calculate_from_rollup( &mut self, - blob_source: BlobSource, - last_block_number: u64, + tx_hash: TxHash, + block_num: U64, ) -> Result<(u64, u64), ScalarError> { //Step1. get_data_from_blob let (l2_data_len, num_blobs, l2_txn) = - self.get_data_from_blob(&blob_source, last_block_number).await.map_err(|e| { + self.get_data_from_blob(tx_hash, block_num).await.map_err(|e| { log::error!("get_data_from_blob error: {:#?}", e); e })?; - let source_tx_receipt = self + let blob_tx_receipt = self .l1_provider - .get_transaction_receipt(blob_source.transaction_hash) + .get_transaction_receipt(tx_hash) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( - "l1 get source transaction receipt return none, tx_hash= {:#?}", - blob_source.transaction_hash + "l1 get transaction receipt return none, tx_hash= {:#?}", + tx_hash ))) })?; - if !receipt_matches_source(&source_tx_receipt, &blob_source) { - return Err(ScalarError::Error(anyhow!( - "original blob source receipt identity mismatch" - ))); - } // rollup_gas_used - let rollup_gas_used = source_tx_receipt.gas_used.unwrap_or_default(); + let rollup_gas_used = blob_tx_receipt.gas_used.unwrap_or_default(); if rollup_gas_used.is_zero() { return Err(ScalarError::Error(anyhow!(format!( "blob tx calldata gas_used is none or 0, tx_hash = {:#?}", - blob_source.transaction_hash + tx_hash )))); } //Step2. Calculate scalar - let commit_scalar = (rollup_gas_used.as_u64() + self.finalize_batch_gas_used) * PRECISION - / l2_txn.max(self.txn_per_batch); + let commit_scalar = (rollup_gas_used.as_u64() + self.finalize_batch_gas_used) * PRECISION / + l2_txn.max(self.txn_per_batch); let blob_scalar = if l2_data_len > 0 { num_blobs.max(1) * MAX_BLOB_TX_PAYLOAD_SIZE as u64 * PRECISION / l2_data_len } else { @@ -851,85 +270,84 @@ impl ScalarUpdater { async fn get_data_from_blob( &self, - source: &BlobSource, - last_block_num: u64, + tx_hash: TxHash, + block_num: U64, ) -> Result<(u64, u64, u64), ScalarError> { let blob_tx = self .l1_provider - .get_transaction(source.transaction_hash) + .get_transaction(tx_hash) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( "l1 get transaction return none, tx_hash: {:#?}", - source.transaction_hash + tx_hash ))) })?; - if blob_tx.to != Some(self.l1_rollup.address()) - || blob_tx.block_number != Some(source.block_number) - || blob_tx.block_hash != Some(source.block_hash) - || blob_tx.transaction_index != Some(source.transaction_index) - { - return Err(ScalarError::Error(anyhow!( - "blob source transaction changed block identity" - ))); - } let blob_block = self .l1_provider - .get_block_with_txs(BlockNumber::Number(source.block_number)) + .get_block_with_txs(BlockNumber::Number(block_num)) .await .map_err(|e| ScalarError::Error(anyhow!(format!("{:#?}", e))))? .ok_or_else(|| { ScalarError::Error(anyhow!(format!( "l1 get block info return none, block_num: {:#?}", - source.block_number + block_num ))) })?; - if blob_block.hash != Some(source.block_hash) { - return Err(ScalarError::Error(anyhow!( - "blob source block hash changed before sidecar lookup" - ))); - } let indexed_hashes = data_and_hashes_from_txs(&blob_block.transactions, &blob_tx); if indexed_hashes.is_empty() { - return Err(ScalarError::Error(anyhow!(format!( - "resolved blob source {:?} has no blob positions", - source.transaction_hash - )))); - } - let actual_hashes: Vec = indexed_hashes.iter().map(|item| item.hash).collect(); - if actual_hashes != source.blob_hashes { - return Err(ScalarError::Error(anyhow!( - "blob positions changed between source resolution and sidecar lookup" - ))); + log::info!("no blob in this batch, batch_tx_hash: {:#?}", tx_hash); + return Ok((0, 0, 0)); } - // The sample is finalized, so the following block (whose parent beacon - // root addresses this execution block's sidecars) must already exist. - let next_block_num = - U64::from( - source.block_number.as_u64().checked_add(1).ok_or_else(|| { - ScalarError::Error(anyhow!("blob source block number overflow")) - })?, - ); - let next_block = self - .l1_provider - .get_block(BlockNumber::Number(next_block_num)) - .await - .map_err(|e| ScalarError::Error(anyhow!(format!("get next L1 block: {e:?}"))))? - .ok_or_else(|| ScalarError::Error(anyhow!("next finalized L1 block is unavailable")))?; - if next_block.parent_hash != source.block_hash { - return Err(ScalarError::Error(anyhow!( - "next L1 block is not the canonical child of the blob source block" - ))); + // Waiting for the next L1 block to be produced. + let next_block_num = block_num + 1; + // Max delay 5 * 3 = 15 secs + let mut retry_times = 5; + let prev_beacon_root = loop { + let blk_info = self.l1_provider.get_block(BlockNumber::Number(next_block_num)).await; + if let Ok(Some(info)) = blk_info { + if let Some(beacon_blk_root) = info.parent_beacon_block_root { + break beacon_blk_root; + } else { + return Err(ScalarError::Error(anyhow!(format!( + "next block info's pre_beacon_root is none, block number: {:?}", + next_block_num + )))); + } + } else if retry_times > 0 { + retry_times -= 1; + sleep(Duration::from_secs(3)).await; + + log::info!( + "request next block info, retry times= {:?}, block number: {:?}", + retry_times, + next_block_num + ); + continue; + } else { + return Err(ScalarError::Error(anyhow!(format!( + "maximum number of requests next block info reached: {:?}, block number:{:?}", + retry_times, next_block_num + )))); + } + }; + + // Parse last_block_num + if blob_tx.input.is_empty() { + log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", tx_hash); + return Err(ScalarError::Error(anyhow!(format!("commitBatch tx.input empty")))); } - let prev_beacon_root = next_block.parent_beacon_block_root.ok_or_else(|| { - ScalarError::Error(anyhow!(format!( - "next block has no parent beacon root, block number: {next_block_num:?}" - ))) - })?; + let param = if let Ok(_param) = CommitBatchCall::decode(&blob_tx.input) { + _param + } else { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); + return Err(ScalarError::Error(anyhow!(format!("decode commitBatch tx.input error",)))); + }; + let last_block_num: u64 = param.batch_data_input.last_block_number; let indexes: Vec = indexed_hashes.iter().map(|item| item.index).collect(); let sidecars_rt = self @@ -940,14 +358,14 @@ impl ScalarUpdater { let sidecars: &Vec = sidecars_rt["data"].as_array().ok_or_else(|| { ScalarError::Error(anyhow!(format!( "blob_sidecars is none, blk_num: {:?}, blk_root: {:?}", - source.block_number, prev_beacon_root + block_num, prev_beacon_root ))) })?; if sidecars.is_empty() { return Err(ScalarError::Error(anyhow!(format!( "blob_sidecars is empty, blk_num: {:?}, blk_root: {:?}", - source.block_number, prev_beacon_root + block_num, prev_beacon_root )))); } @@ -959,11 +377,7 @@ impl ScalarUpdater { let origin_batch = extract_tx_payload(indexed_hashes, sidecars)?; let batch_size = origin_batch.len() as u64; - let txn_count = extract_txn_count(&origin_batch, last_block_num).ok_or_else(|| { - ScalarError::CalculateError(anyhow!( - "blob payload block range does not match canonical lastBlockNumber" - )) - })?; + let txn_count = extract_txn_count(&origin_batch, last_block_num).unwrap_or_default(); Ok((batch_size, num_blobs, txn_count)) } @@ -975,142 +389,6 @@ mod tests { use super::*; use std::{env::var, str::FromStr, sync::Arc}; - #[test] - fn v2_blob_commitment_preserves_order() { - let a = H256::from_low_u64_be(1); - let b = H256::from_low_u64_be(2); - assert_ne!(blob_commitment(2, &[a, b]).unwrap(), blob_commitment(2, &[b, a]).unwrap()); - assert!(blob_commitment(2, &[]).is_err()); - assert!(blob_commitment(1, &[a, b]).is_err()); - } - - #[test] - fn fresh_blob_survives_mapping_gc_but_not_a_nonzero_mismatch() { - let actual = H256::from_low_u64_be(7); - assert!(validate_fresh_blob_commitment(H256::zero(), actual).is_ok()); - assert!(validate_fresh_blob_commitment(actual, actual).is_ok()); - assert!(validate_fresh_blob_commitment(H256::from_low_u64_be(8), actual).is_err()); - } - - #[test] - fn mapping_gc_recovery_prefers_snapshot_then_canonical_block() { - let snapshot = H256::from_low_u64_be(1); - let historical = H256::from_low_u64_be(2); - assert_eq!(recover_gc_commitment(snapshot, historical), snapshot); - assert_eq!(recover_gc_commitment(H256::zero(), historical), historical); - assert_eq!(recover_gc_commitment(H256::zero(), H256::zero()), H256::zero()); - } - - #[test] - fn zero_blobless_classification_preserves_legacy_but_rejects_current_commit_batch() { - assert_eq!( - classify_blobless_submission( - 0, - SubmissionKind::CommitBatch, - true, - ZERO_VERSIONED_HASH, - ) - .unwrap(), - BloblessDisposition::ExcludeZero - ); - assert_eq!( - classify_blobless_submission( - 1, - SubmissionKind::CommitBatchWithProof, - false, - ZERO_VERSIONED_HASH, - ) - .unwrap(), - BloblessDisposition::ExcludeZero - ); - assert_eq!( - classify_blobless_submission(1, SubmissionKind::CommitState, false, H256::zero(),) - .unwrap(), - BloblessDisposition::ExcludeMissing - ); - assert!(classify_blobless_submission( - 1, - SubmissionKind::CommitBatch, - false, - ZERO_VERSIONED_HASH, - ) - .is_err()); - } - - #[test] - fn blob_source_dedup_uses_full_stable_identity() { - let source = BlobSource { - transaction_hash: H256::from_low_u64_be(1), - block_number: 10.into(), - block_hash: H256::from_low_u64_be(10), - transaction_index: 0.into(), - blob_hashes: vec![H256::from_low_u64_be(11)], - }; - let mut sources = HashSet::new(); - assert!(sources.insert(source.clone())); - assert!(!sources.insert(source.clone())); - - let mut orphan_replacement = source; - orphan_replacement.block_hash = H256::from_low_u64_be(12); - assert!(sources.insert(orphan_replacement)); - } - - #[test] - fn source_receipt_must_match_full_stable_identity() { - let source = BlobSource { - transaction_hash: H256::from_low_u64_be(1), - block_number: 10.into(), - block_hash: H256::from_low_u64_be(10), - transaction_index: 2.into(), - blob_hashes: vec![H256::from_low_u64_be(11)], - }; - let mut receipt = TransactionReceipt { - transaction_hash: source.transaction_hash, - block_number: Some(source.block_number), - block_hash: Some(source.block_hash), - transaction_index: source.transaction_index, - ..Default::default() - }; - assert!(receipt_matches_source(&receipt, &source)); - receipt.block_hash = Some(H256::from_low_u64_be(12)); - assert!(!receipt_matches_source(&receipt, &source)); - } - - #[test] - fn commit_window_indices_are_unique_and_bounded() { - let topic0 = H256::from_low_u64_be(1); - let make_log = |index: u64| Log { - topics: vec![topic0, H256::from_low_u64_be(index)], - ..Default::default() - }; - let removed = Log { removed: Some(true), ..make_log(2) }; - let indices = batch_indices_from_commit_logs( - &[make_log(1), make_log(1), removed, make_log(3), make_log(9)], - 3, - ); - assert_eq!(indices.into_iter().collect::>(), vec![1, 3]); - } - - #[test] - fn historical_commit_replay_is_indexed_once_by_batch() { - let make_log = |index: u64| Log { - topics: vec![H256::zero(), H256::from_low_u64_be(index)], - ..Default::default() - }; - let removed = Log { removed: Some(true), ..make_log(2) }; - let index = index_commit_logs(vec![make_log(1), make_log(1), make_log(2), removed]); - assert_eq!(index.get(&1).unwrap().len(), 2); - assert_eq!(index.get(&2).unwrap().len(), 1); - } - - #[test] - fn changed_snapshot_hash_fails_closed() { - let expected = H256::from_low_u64_be(1); - assert!(ensure_snapshot_hash(expected, Some(expected)).is_ok()); - assert!(ensure_snapshot_hash(expected, Some(H256::from_low_u64_be(2))).is_err()); - assert!(ensure_snapshot_hash(expected, None).is_err()); - } - #[tokio::test] #[ignore] async fn test_calculate_from_current_rollup() { @@ -1158,7 +436,6 @@ mod tests { .expect("Cannot detect GAS_ORACLE_L1_BEACON_RPC env empty") .parse() .expect("Cannot parse GAS_ORACLE_L1_BEACON_RPC env var empty"), - 1u64, gas_threshold, 0u64, 0u64, @@ -1166,16 +443,8 @@ mod tests { 50u64, ); - let source_tx = - overhead.l1_provider.get_transaction(rollup_tx_hash).await.unwrap().unwrap(); - let source = BlobSource { - transaction_hash: rollup_tx_hash, - block_number: rollup_tx_block_num, - block_hash: source_tx.block_hash.unwrap(), - transaction_index: source_tx.transaction_index.unwrap(), - blob_hashes: transaction_blob_hashes(&source_tx), - }; - let latest_overhead = overhead.calculate_from_rollup(source, 0).await; + let latest_overhead = + overhead.calculate_from_rollup(rollup_tx_hash, rollup_tx_block_num).await; log::info!("latest_overhead: {:#?}", latest_overhead); } diff --git a/gas-oracle/app/src/da_scalar/mod.rs b/gas-oracle/app/src/da_scalar/mod.rs index ddc6862df..ae0ed3313 100644 --- a/gas-oracle/app/src/da_scalar/mod.rs +++ b/gas-oracle/app/src/da_scalar/mod.rs @@ -4,7 +4,7 @@ mod calculate; mod error; #[allow(clippy::module_inception)] pub mod l1_scalar; -mod typed_tx; mod zstd_util; +mod typed_tx; const MAX_BLOB_TX_PAYLOAD_SIZE: usize = 131072; // 131072 = 4096 * 32 = 1024 * 4 * 32 = 128kb diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index ebff1bfed..74655abb3 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -4,6 +4,7 @@ use crate::{ l1_base_fee::BaseFeeUpdater, read_parse_env, }; +use remote_signer_client::SignerClient; use ethers::{ prelude::*, providers::{Http, Provider}, @@ -11,7 +12,6 @@ use ethers::{ types::Address, }; use eyre::anyhow; -use remote_signer_client::SignerClient; use std::{env::var, error::Error, str::FromStr, sync::Arc, time::Duration}; use tokio::time::sleep; @@ -31,7 +31,6 @@ struct Config { interval: u64, overhead_interval: u64, l1_rollup_address: Address, - l1_rollup_deploy_block: u64, l2_oracle_address: Address, private_key: String, l1_beacon_rpc: String, @@ -59,7 +58,6 @@ impl Config { interval: read_parse_env("INTERVAL"), overhead_interval: read_parse_env("OVERHEAD_INTERVAL"), l1_rollup_address: Address::from_str(&var("L1_ROLLUP").expect("L1_ROLLUP env"))?, - l1_rollup_deploy_block: read_parse_env("GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK"), l2_oracle_address: Address::from_str( &var("L2_GAS_PRICE_ORACLE").expect("L2_GAS_PRICE_ORACLE env"), )?, @@ -127,12 +125,6 @@ fn check_config(config: &Config) -> Result<(), Box> { if config.txn_per_batch < 10u64 { return Err(anyhow!("Check env config error, TXN_PER_BATCH should be more than 10").into()); } - if config.l1_rollup_deploy_block == 0 { - return Err(anyhow!( - "Check env config error, GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK must be non-zero" - ) - .into()); - } Ok(()) } @@ -227,7 +219,6 @@ async fn prepare_updater( ext_signer, l1_rollup, config.l1_beacon_rpc.clone(), - config.l1_rollup_deploy_block, config.gas_threshold, config.commit_scalar_buffer, config.blob_scalar_buffer, @@ -261,7 +252,6 @@ fn register_metrics() { REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.commit_scalar.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.blob_scalar.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.txn_per_batch.clone())).unwrap(); - REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.da_sample_exclusions.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.gas_oracle_owner_balance.clone())).unwrap(); REGISTRY.register(Box::new(ORACLE_SERVICE_METRICS.l1_rpc_status.clone())).unwrap(); } diff --git a/gas-oracle/app/src/l1_base_fee.rs b/gas-oracle/app/src/l1_base_fee.rs index 699bd6891..833e018a6 100644 --- a/gas-oracle/app/src/l1_base_fee.rs +++ b/gas-oracle/app/src/l1_base_fee.rs @@ -145,8 +145,9 @@ impl BaseFeeUpdater { let client: Arc, LocalWallet>> = self.l2_oracle.client(); if need_update { // Update calldata basefee and blob baseFee - let call = - self.l2_oracle.set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee); + let call = self + .l2_oracle + .set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee); let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) .await .map_err(|e| { @@ -214,11 +215,11 @@ async fn query_l1_base_fee( return Err(OracleError::L1BaseFeeError(anyhow!(format!( "Failed to query l1_gas_price: {:#?}", e - )))); + )))) } }; - Ok((l1_base_fee, latest_blob_fee, gas_price)) + Ok((l1_base_fee, U256::from(latest_blob_fee), gas_price)) } #[tokio::test] diff --git a/gas-oracle/app/src/lib.rs b/gas-oracle/app/src/lib.rs index 385121cbd..60e6fa0de 100644 --- a/gas-oracle/app/src/lib.rs +++ b/gas-oracle/app/src/lib.rs @@ -5,7 +5,6 @@ mod error; pub mod gas_price_oracle; mod l1_base_fee; mod metrics; -mod rollup_compat; mod da_scalar; mod signer; @@ -39,4 +38,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:#?}", e) }; error_msg -} +} \ No newline at end of file diff --git a/gas-oracle/app/src/metrics.rs b/gas-oracle/app/src/metrics.rs index de9d520fa..f6201e4e2 100644 --- a/gas-oracle/app/src/metrics.rs +++ b/gas-oracle/app/src/metrics.rs @@ -1,5 +1,5 @@ use lazy_static::lazy_static; -use prometheus::{Gauge, IntCounter, IntGauge, Registry}; +use prometheus::{Gauge, IntGauge, Registry}; pub struct OracleServiceMetrics { pub l1_base_fee: Gauge, @@ -10,7 +10,6 @@ pub struct OracleServiceMetrics { pub commit_scalar: IntGauge, pub blob_scalar: Gauge, pub txn_per_batch: Gauge, - pub da_sample_exclusions: IntCounter, pub l1_rpc_status: IntGauge, } @@ -28,11 +27,6 @@ lazy_static! { .expect("metric can be created"), blob_scalar: Gauge::new("blobScalar", "blob scalar").expect("metric can be created"), txn_per_batch: Gauge::new("txnPerBatch", "txn per batch").expect("metric can be created"), - da_sample_exclusions: IntCounter::new( - "daSampleExclusions", - "canonical DA samples excluded because their source was absent, duplicate, or unverifiable", - ) - .expect("metric can be created"), gas_oracle_owner_balance: Gauge::new("gasOracleOwnerBalance", "gas oracle owner balance") .expect("metric can be created"), l1_rpc_status: IntGauge::new("l1RpcStatus", "l1 prc").expect("metric can be created"), diff --git a/gas-oracle/app/src/rollup_compat.rs b/gas-oracle/app/src/rollup_compat.rs deleted file mode 100644 index b31a5f89c..000000000 --- a/gas-oracle/app/src/rollup_compat.rs +++ /dev/null @@ -1,299 +0,0 @@ -use ethers::{ - abi::AbiDecode, - contract::EthCall, - providers::Middleware, - types::{Address, BlockId, BlockNumber, Filter, Log, TxHash, H256, U256, U64}, - utils::keccak256, -}; -use eyre::{eyre, Result}; - -use crate::abi::{ - pre_submitter_rollup_abi::{ - CommitBatchCall as PreSubmitterCommitBatchCall, - CommitBatchWithProofCall as PreSubmitterCommitBatchWithProofCall, - CommitStateCall as PreSubmitterCommitStateCall, - }, - rollup_abi::{CommitBatchCall, CommitBatchWithProofCall, CommitStateCall, Rollup}, -}; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[allow(clippy::enum_variant_names)] -pub enum SubmissionKind { - CommitBatch, - CommitState, - CommitBatchWithProof, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BatchDataInput { - pub version: u8, - pub last_block_number: u64, - pub kind: SubmissionKind, - pub pre_submitter: bool, -} - -macro_rules! decoded { - ($input:expr, $kind:expr, $pre:expr) => {{ - let input = $input; - BatchDataInput { - version: input.version, - last_block_number: input.last_block_number, - kind: $kind, - pre_submitter: $pre, - } - }}; -} - -/// Decode only the batch fields consumed by the oracle. The selector is -/// matched before ABI decoding so malformed or unknown calldata fails closed. -pub fn decode_batch_data_input(data: &[u8]) -> Result { - let selector = - data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; - - if selector == CommitBatchCall::selector() { - let call = CommitBatchCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, false)); - } - if selector == CommitStateCall::selector() { - let call = CommitStateCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, false)); - } - if selector == CommitBatchWithProofCall::selector() { - let call = CommitBatchWithProofCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, false)); - } - if selector == PreSubmitterCommitBatchCall::selector() { - let call = PreSubmitterCommitBatchCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, true)); - } - if selector == PreSubmitterCommitStateCall::selector() { - let call = PreSubmitterCommitStateCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, true)); - } - if selector == PreSubmitterCommitBatchWithProofCall::selector() { - let call = PreSubmitterCommitBatchWithProofCall::decode(data)?; - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, true)); - } - - Err(eyre!("unsupported rollup submission selector")) -} - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct LogIdentity { - pub block_number: u64, - pub transaction_index: u64, - pub log_index: u64, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CanonicalCommit { - pub identity: LogIdentity, - pub transaction_hash: TxHash, - pub block_hash: H256, - pub batch_hash: H256, -} - -fn identity(log: &Log) -> Option { - Some(LogIdentity { - block_number: log.block_number?.as_u64(), - transaction_index: log.transaction_index?.as_u64(), - log_index: log.log_index?.as_u64(), - }) -} - -/// Select the last same-batch Commit after the last Revert. Full log identity -/// deliberately distinguishes a same-hash recommit from the reverted event. -pub fn select_canonical_commit( - commits: &[Log], - reverts: &[Log], - canonical_hash: H256, -) -> Option { - if canonical_hash.is_zero() { - return None; - } - let last_revert = - reverts.iter().filter(|log| !log.removed.unwrap_or_default()).filter_map(identity).max(); - - commits - .iter() - .filter(|log| !log.removed.unwrap_or_default()) - .filter_map(|log| { - let identity = identity(log)?; - if last_revert.is_some_and(|revert| identity <= revert) { - return None; - } - if log.topics.len() < 3 || log.topics[2] != canonical_hash { - return None; - } - Some(CanonicalCommit { - identity, - transaction_hash: log.transaction_hash?, - block_hash: log.block_hash?, - batch_hash: log.topics[2], - }) - }) - .max_by_key(|commit| commit.identity) -} - -pub const LOG_QUERY_RANGE: u64 = 10_000; - -pub async fn query_batch_logs( - provider: &M, - rollup: Address, - batch_index: u64, - event_topic: H256, - from_block: u64, - to_block: u64, -) -> Result> { - if from_block > to_block { - return Ok(Vec::new()); - } - let mut logs = Vec::new(); - let mut from = from_block; - loop { - let to = from.saturating_add(LOG_QUERY_RANGE - 1).min(to_block); - let filter = Filter::new() - .address(rollup) - .from_block(from) - .to_block(to) - .topic0(event_topic) - .topic1(U256::from(batch_index)); - logs.extend(provider.get_logs(&filter).await.map_err(|err| eyre!(err.to_string()))?); - if to == to_block { - break; - } - from = to + 1; - } - Ok(logs) -} - -pub async fn resolve_canonical_commit( - rollup: &Rollup, - provider: &M, - batch_index: u64, - from_block: u64, - snapshot_number: U64, -) -> Result> { - let before = provider - .get_block(snapshot_number) - .await - .map_err(|err| eyre!(err.to_string()))? - .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; - let before_hash = before.hash.ok_or_else(|| eyre!("snapshot block has no hash"))?; - let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); - let canonical_hash: H256 = rollup - .committed_batches(U256::from(batch_index)) - .block(block_id) - .call() - .await - .map_err(|err| eyre!(err.to_string()))? - .into(); - if canonical_hash.is_zero() { - return Ok(None); - } - - let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); - let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); - let commits = query_batch_logs( - provider, - rollup.address(), - batch_index, - commit_topic, - from_block, - snapshot_number.as_u64(), - ) - .await?; - let reverts = query_batch_logs( - provider, - rollup.address(), - batch_index, - revert_topic, - from_block, - snapshot_number.as_u64(), - ) - .await?; - - let after = provider - .get_block(snapshot_number) - .await - .map_err(|err| eyre!(err.to_string()))? - .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; - if after.hash != Some(before_hash) { - return Err(eyre!("snapshot block hash changed during canonical resolution")); - } - - Ok(select_canonical_commit(&commits, &reverts, canonical_hash)) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn log(block: u64, marker: u64, hash: H256) -> Log { - Log { - block_number: Some(block.into()), - transaction_index: Some(0.into()), - log_index: Some(0.into()), - transaction_hash: Some(H256::from_low_u64_be(marker)), - block_hash: Some(H256::from_low_u64_be(block)), - topics: vec![H256::zero(), H256::from_low_u64_be(7), hash], - ..Default::default() - } - } - - #[test] - fn rejects_short_and_unknown_calldata() { - assert!(decode_batch_data_input(&[]).is_err()); - assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - } - - #[test] - fn decodes_shared_pre_and_post_submitter_fixtures() { - let corpus: serde_json::Value = serde_json::from_str(include_str!( - "../../../node/derivation/testdata/rollup_calldata_fixtures.json" - )) - .unwrap(); - let mut decoded_count = 0; - for fixture in corpus["fixtures"].as_array().unwrap() { - let epoch = fixture["epoch"].as_str().unwrap(); - if epoch != "pre-submitter" && epoch != "current" { - continue; - } - let data = ethers::utils::hex::decode( - fixture["data"].as_str().unwrap().trim_start_matches("0x"), - ) - .unwrap(); - let decoded = decode_batch_data_input(&data) - .unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); - assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); - assert_eq!( - decoded.last_block_number, - fixture["expected"]["lastBlockNumber"].as_u64().unwrap() - ); - decoded_count += 1; - } - assert_eq!(decoded_count, 6); - } - - #[test] - fn selector_sets_are_frozen() { - assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); - assert_eq!(CommitStateCall::selector(), [0x67, 0xca, 0xa3, 0x7a]); - assert_eq!(CommitBatchWithProofCall::selector(), [0x15, 0x44, 0xba, 0x3a]); - assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); - assert_eq!(PreSubmitterCommitStateCall::selector(), [0x1e, 0x88, 0x25, 0xbe]); - assert_eq!(PreSubmitterCommitBatchWithProofCall::selector(), [0x4e, 0x8f, 0x1d, 0x67]); - } - - #[test] - fn same_hash_recommit_after_revert_wins() { - let hash = H256::from_low_u64_be(99); - let resolved = select_canonical_commit( - &[log(10, 1, hash), log(12, 3, hash)], - &[log(11, 2, hash)], - hash, - ) - .unwrap(); - assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); - } -} diff --git a/gas-oracle/app/src/signer.rs b/gas-oracle/app/src/signer.rs index 34db74586..7eb865a34 100644 --- a/gas-oracle/app/src/signer.rs +++ b/gas-oracle/app/src/signer.rs @@ -122,6 +122,8 @@ fn eip1559_estimator(base_fee_per_gas: U256, _rewards: Vec>) -> (U256, (max_fee_per_gas, max_priority_fee_per_gas) } + + #[tokio::test] #[ignore] async fn test_estimate_eip1559_fees() { @@ -149,7 +151,6 @@ async fn test_estimate_eip1559_fees() { let tx_typed = tx.as_eip1559_mut().unwrap(); log::info!( "====tx_typed gas data: {:?}, {:?}", - tx_typed.max_fee_per_gas, - tx_typed.max_priority_fee_per_gas + tx_typed.max_fee_per_gas, tx_typed.max_priority_fee_per_gas ); } diff --git a/node/cmd/node/main.go b/node/cmd/node/main.go index e9148ffaf..08c1c5c4d 100644 --- a/node/cmd/node/main.go +++ b/node/cmd/node/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "encoding/binary" "fmt" "net" "net/http" @@ -18,7 +17,6 @@ import ( "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" "github.com/prometheus/client_golang/prometheus/promhttp" - tmconfig "github.com/tendermint/tendermint/config" tmcrypto "github.com/tendermint/tendermint/crypto" tmlog "github.com/tendermint/tendermint/libs/log" tmnode "github.com/tendermint/tendermint/node" @@ -138,9 +136,6 @@ func L2NodeMain(ctx *cli.Context) error { if err != nil { return err } - if err := restorePersistedUpgradeHeight(tmCfg); err != nil { - return fmt.Errorf("restore persisted sequencer upgrade height: %w", err) - } // Load derivation config here (not just before the switch below): its // VerifyMode decides whether this node runs the Tendermint consensus node, @@ -166,14 +161,25 @@ func L2NodeMain(ctx *cli.Context) error { pubKey, _ = tmVal.GetPubKey() } - // Reuse the shared syncer instance. NewExecutor starts it independently of - // validator membership, and Derivation.Start may safely invoke Start again. + // Reuse the shared syncer instance -- DevSequencer mode is the only path + // that pulls a syncer out of NewExecutor, so we hand back the same one + // rather than letting NewExecutor open a second store + syncer. newSyncerFunc := func() (*sync.Syncer, error) { return syncer, nil } executor, err = node.NewExecutor(newSyncerFunc, nodeConfig, pubKey) if err != nil { return err } + // Eagerly start the L1 message syncer for post-upgrade sequencer nodes that + // are NOT in the PBFT validator set (separated-deployment / HA cluster). + // In the combined-deployment case, updateSequencerSet already started the + // syncer inside NewExecutor, so SetSyncer is a no-op there. + if signer != nil && executor.Syncer() == nil { + executor.SetSyncer(syncer) + syncer.Start() + nodeConfig.Logger.Info("L1 syncer start", "reason", "post-upgrade always start") + } + haService, err = initHAService(ctx, home, nodeConfig.Logger) if err != nil { return err @@ -290,46 +296,6 @@ func L2NodeMain(ctx *cli.Context) error { return nil } -// upgradeHeightSnapshotStore holds the height restored from Tendermint's state -// DB while NewExecutor is constructed. SetupNode subsequently rewires the -// upgrade package to the live DB. An unexpected early write fails hard instead -// of pretending that critical consensus state was persisted. -type upgradeHeightSnapshotStore struct { - height int64 -} - -func (s upgradeHeightSnapshotStore) Get([]byte) ([]byte, error) { - if s.height < 0 { - return nil, nil - } - var encoded [8]byte - binary.BigEndian.PutUint64(encoded[:], uint64(s.height)) - return encoded[:], nil -} - -func (upgradeHeightSnapshotStore) Set([]byte, []byte) error { - return fmt.Errorf("live Tendermint upgrade store is not wired yet") -} - -// restorePersistedUpgradeHeight makes the persisted H available before -// NewExecutor performs its initial validator lookup. Tendermint normally wires -// this store inside NewNode, which is necessarily constructed after Executor. -func restorePersistedUpgradeHeight(tmCfg *tmconfig.Config) error { - stateDB, err := tmnode.DefaultDBProvider(&tmnode.DBContext{ID: "state", Config: tmCfg}) - if err != nil { - return err - } - if err := upgrade.SetStore(stateDB); err != nil { - _ = stateDB.Close() - return err - } - height := upgrade.UpgradeBlockHeight() - if err := stateDB.Close(); err != nil { - return err - } - return upgrade.SetStore(upgradeHeightSnapshotStore{height: height}) -} - // initHAService builds the HA config and creates the HAService. // Loading order: defaults → config file → flag overrides → auto-resolve → validate. // Returns nil (no error) if HA is not enabled. diff --git a/node/core/centralization_cleanup_test.go b/node/core/centralization_cleanup_test.go deleted file mode 100644 index c7f0ea859..000000000 --- a/node/core/centralization_cleanup_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package node - -import ( - "bytes" - "errors" - "os" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/upgrade" - - nodesync "morph-l2/node/sync" -) - -func TestParseStaticValidatorTmKeys(t *testing.T) { - keyA := strings.Repeat("11", tmKeySize) - keyB := strings.Repeat("22", tmKeySize) - - keysAB, hashAB, err := parseStaticValidatorTmKeys([]string{keyB, "0x" + keyA}) - require.NoError(t, err) - require.Len(t, keysAB, 2) - require.True(t, bytes.Compare(keysAB[0], keysAB[1]) < 0, "keys must be canonicalized lexicographically") - - keysBA, hashBA, err := parseStaticValidatorTmKeys([]string{keyA + "," + keyB}) - require.NoError(t, err) - require.Equal(t, keysAB, keysBA) - require.Equal(t, hashAB, hashBA, "input order must not change the network key-set hash") - - for _, tc := range []struct { - name string - values []string - }{ - {name: "empty"}, - {name: "short", values: []string{"01"}}, - {name: "invalid hex", values: []string{strings.Repeat("zz", tmKeySize)}}, - {name: "duplicate", values: []string{keyA, "0x" + keyA}}, - } { - t.Run(tc.name, func(t *testing.T) { - _, _, err := parseStaticValidatorTmKeys(tc.values) - require.Error(t, err) - }) - } -} - -func TestValidatorSetAtHeightUpgradeBoundary(t *testing.T) { - originalHeight := upgrade.UpgradeBlockHeight() - upgrade.SetUpgradeBlockHeight(100) - t.Cleanup(func() { upgrade.SetUpgradeBlockHeight(originalHeight) }) - - legacyKeys := [][]byte{bytes.Repeat([]byte{0x11}, tmKeySize)} - staticKeys := [][]byte{bytes.Repeat([]byte{0x22}, tmKeySize)} - legacyCalls := 0 - executor := &Executor{ - staticValidatorTmKeys: staticKeys, - legacyValidatorSetAtHeightFunc: func(int64) ([][]byte, error) { - legacyCalls++ - return cloneValidatorKeys(legacyKeys), nil - }, - } - - for _, height := range []uint64{99, 100} { - got, err := executor.validatorSetAtHeight(height) - require.NoError(t, err) - require.Equal(t, legacyKeys, got) - } - got, err := executor.validatorSetAtHeight(101) - require.NoError(t, err) - require.Equal(t, staticKeys, got) - require.Equal(t, 2, legacyCalls, "H+1 must not call either historical contract") - - got[0][0] ^= 0xff - require.Equal(t, byte(0x22), executor.staticValidatorTmKeys[0][0], "callers must not mutate the configured set") -} - -func TestEnsureSyncerStartedIndependentOfValidatorMembership(t *testing.T) { - created := 0 - fakeSyncer := nodesync.NewFakeSyncer(nil) - executor := &Executor{ - newSyncerFunc: func() (*nodesync.Syncer, error) { - created++ - return fakeSyncer, nil - }, - } - - require.NoError(t, executor.ensureSyncerStarted()) - require.NoError(t, executor.ensureSyncerStarted()) - require.Equal(t, 1, created) - require.Same(t, fakeSyncer, executor.l1MsgReader) -} - -func TestEnsureSyncerStartedKeepsFactoryError(t *testing.T) { - created := 0 - wantErr := errors.New("factory failed") - executor := &Executor{ - newSyncerFunc: func() (*nodesync.Syncer, error) { - created++ - return nil, wantErr - }, - } - - require.ErrorIs(t, executor.ensureSyncerStarted(), wantErr) - require.ErrorIs(t, executor.ensureSyncerStarted(), wantErr) - require.Equal(t, 1, created) - require.Nil(t, executor.l1MsgReader) -} - -func TestAllValidatorEntryPointsUseUnifiedResolver(t *testing.T) { - source, err := os.ReadFile("executor.go") - require.NoError(t, err) - require.Equal(t, 3, strings.Count(string(source), ".validatorSetAtHeight("), - "NewExecutor and both DeliverBlock branches must use the H/H+1 resolver") -} diff --git a/node/core/config.go b/node/core/config.go index 72e91d37d..c3276cdec 100644 --- a/node/core/config.go +++ b/node/core/config.go @@ -1,20 +1,16 @@ package node import ( - "bytes" "crypto/rand" - "encoding/hex" "errors" "fmt" "io" "os" "path/filepath" - "slices" "strings" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/common/hexutil" - gethcrypto "github.com/morph-l2/go-ethereum/crypto" tmconfig "github.com/tendermint/tendermint/config" tmflags "github.com/tendermint/tendermint/libs/cli/flags" tmlog "github.com/tendermint/tendermint/libs/log" @@ -37,9 +33,7 @@ type Config struct { L2StakingAddress common.Address `json:"l2staking_address"` MaxL1MessageNumPerBlock uint64 `json:"max_l1_message_num_per_block"` BlsKeyCheckForkHeight uint64 `json:"bls_key_check_fork_height"` - StaticValidatorTmKeys [][]byte `json:"static_validator_tm_keys"` - StaticValidatorKeySetHash common.Hash `json:"static_validator_key_set_hash"` - StaticValidatorKeySource string `json:"static_validator_key_source"` + DevSequencer bool `json:"dev_sequencer"` Logger tmlog.Logger `json:"logger"` } @@ -148,13 +142,9 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { } } - keys, keySetHash, err := parseStaticValidatorTmKeys(ctx.GlobalStringSlice(flags.StaticValidatorTmKeys.Name)) - if err != nil { - return fmt.Errorf("invalid --%s: %w", flags.StaticValidatorTmKeys.Name, err) + if ctx.GlobalIsSet(flags.DevSequencer.Name) { + c.DevSequencer = ctx.GlobalBool(flags.DevSequencer.Name) } - c.StaticValidatorTmKeys = keys - c.StaticValidatorKeySetHash = keySetHash - c.StaticValidatorKeySource = "cli/env" if ctx.GlobalIsSet(flags.MainnetFlag.Name) { c.BlsKeyCheckForkHeight = MainnetBlsKeyCheckForkHeight @@ -163,47 +153,3 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { return nil } - -// parseStaticValidatorTmKeys validates and canonicalizes the network-wide -// Tendermint ed25519 validator key set. Keys are fixed-width, so hashing the -// sorted concatenation is unambiguous and gives operators a compact value to -// compare across every node before the upgrade boundary is activated. -func parseStaticValidatorTmKeys(values []string) ([][]byte, common.Hash, error) { - var encodedKeys []string - for _, value := range values { - for _, key := range strings.Split(value, ",") { - if key = strings.TrimSpace(key); key != "" { - encodedKeys = append(encodedKeys, key) - } - } - } - if len(encodedKeys) == 0 { - return nil, common.Hash{}, errors.New("at least one Tendermint ed25519 public key is required") - } - - keys := make([][]byte, 0, len(encodedKeys)) - seen := make(map[string]struct{}, len(encodedKeys)) - for i, encoded := range encodedKeys { - encoded = strings.TrimPrefix(encoded, "0x") - if len(encoded) != tmKeySize*2 { - return nil, common.Hash{}, fmt.Errorf("key %d must decode to exactly %d bytes", i, tmKeySize) - } - key, err := hex.DecodeString(encoded) - if err != nil { - return nil, common.Hash{}, fmt.Errorf("key %d is not valid hex: %w", i, err) - } - fingerprint := string(key) - if _, ok := seen[fingerprint]; ok { - return nil, common.Hash{}, fmt.Errorf("key %d duplicates another Tendermint ed25519 public key", i) - } - seen[fingerprint] = struct{}{} - keys = append(keys, key) - } - - slices.SortFunc(keys, bytes.Compare) - canonical := make([]byte, 0, len(keys)*tmKeySize) - for _, key := range keys { - canonical = append(canonical, key...) - } - return keys, gethcrypto.Keccak256Hash(canonical), nil -} diff --git a/node/core/executor.go b/node/core/executor.go index 304340bb6..0c581973e 100644 --- a/node/core/executor.go +++ b/node/core/executor.go @@ -17,7 +17,6 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/l2node" tmlog "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/upgrade" "morph-l2/bindings/bindings" "morph-l2/node/sync" @@ -36,8 +35,6 @@ type Executor struct { newSyncerFunc NewSyncerFunc syncer *sync.Syncer - syncerOnce syncos.Once - syncerErr error sequencerCaller *bindings.SequencerCaller l2StakingCaller *bindings.L2StakingCaller @@ -45,15 +42,10 @@ type Executor struct { currentSeqHash *[32]byte seqTmKeySet map[[tmKeySize]byte]struct{} - nextValidators [][]byte - staticValidatorTmKeys [][]byte - tmPubKey []byte - isSequencer bool - - // legacyValidatorSetAtHeightFunc is a test-only seam for exercising the - // persisted H/H+1 boundary without an L2 RPC. Production leaves it nil and - // uses the protected historical getter body below. - legacyValidatorSetAtHeightFunc func(int64) ([][]byte, error) + nextValidators [][]byte + tmPubKey []byte + isSequencer bool + devSequencer bool blsKeyCheckForkHeight uint64 @@ -110,30 +102,28 @@ func NewExecutor(newSyncFunc NewSyncerFunc, config *Config, tmPubKey crypto.PubK nextL1MsgIndex: index, maxL1MsgNumPerBlock: config.MaxL1MessageNumPerBlock, newSyncerFunc: newSyncFunc, - staticValidatorTmKeys: cloneValidatorKeys(config.StaticValidatorTmKeys), + devSequencer: config.DevSequencer, blsKeyCheckForkHeight: config.BlsKeyCheckForkHeight, logger: logger, metrics: PrometheusMetrics("morphnode"), } - // Resolve the validator set through the same persisted H/H+1 boundary used - // by both DeliverBlock paths. At H the historical contracts still apply; - // H+1 and later never call those contracts. - currentHeight, err := l2Client.BlockNumber(context.Background()) - if err != nil { - return nil, err + if config.DevSequencer { + executor.syncer, err = executor.newSyncerFunc() + if err != nil { + return nil, err + } + //executor.syncer.Start() + executor.l1MsgReader = executor.syncer + return executor, nil } - executor.nextValidators, err = executor.validatorSetAtHeight(currentHeight) + + // Get current height for initial sequencer set update + currentHeight, err := l2Client.BlockNumber(context.Background()) if err != nil { return nil, err } - logger.Info("static validator configuration", - "keyCount", len(config.StaticValidatorTmKeys), - "keySetHash", config.StaticValidatorKeySetHash.Hex(), - "keySetHashAlgorithm", "keccak256(sorted-concat-32-byte-keys)", - "upgradeHeight", upgrade.UpgradeBlockHeight(), - "source", config.StaticValidatorKeySource) - if err := executor.ensureSyncerStarted(); err != nil { + if _, err = executor.updateSequencerSet(currentHeight); err != nil { return nil, err } @@ -274,7 +264,10 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n if wrappedBlock.Number <= height { e.logger.Info("block already delivered by geth (via P2P sync)", "block_number", wrappedBlock.Number) - return e.validatorSetAtHeight(wrappedBlock.Number) + if e.devSequencer { + return consensusData.ValidatorSet, nil + } + return e.getValidatorsAtHeight(int64(wrappedBlock.Number)) } // We only accept the continuous blocks for now. @@ -314,9 +307,11 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n e.updateNextL1MessageIndex(l2Block) - newValidatorSet, err := e.validatorSetAtHeight(l2Block.Number) - if err != nil { - return nil, err + newValidatorSet := consensusData.ValidatorSet + if !e.devSequencer { + if newValidatorSet, err = e.updateSequencerSet(l2Block.Number); err != nil { + return nil, err + } } e.metrics.Height.Set(float64(l2Block.Number)) @@ -380,14 +375,17 @@ func (e *Executor) L2Client() *types.RetryableClient { } // Syncer returns the current L1 message syncer instance, or nil if not yet -// initialized. +// initialized. Callers can use this to detect whether the syncer has already +// been set up (e.g. by updateSequencerSet in the PBFT-validator path) and +// avoid creating a duplicate. func (e *Executor) Syncer() *sync.Syncer { return e.syncer } // SetSyncer installs a pre-built syncer on the executor and wires it in as the -// l1MsgReader. ensureSyncerStarted will start the installed instance instead -// of invoking the factory. +// l1MsgReader. This is intended for the V2/HA separated-deployment case, where +// a node holds a sequencer signer but is not a PBFT validator, so the normal +// lazy-init path in updateSequencerSet never fires. // // The call is idempotent: if a syncer is already set, it is left untouched. func (e *Executor) SetSyncer(s *sync.Syncer) { @@ -398,32 +396,6 @@ func (e *Executor) SetSyncer(s *sync.Syncer) { e.l1MsgReader = s } -// ensureSyncerStarted wires and starts the L1 message reader independently of -// validator membership. Both this guard and Syncer.Start are idempotent: the -// former prevents duplicate construction, while the latter tolerates the -// derivation service invoking Start on the shared instance as well. -func (e *Executor) ensureSyncerStarted() error { - e.syncerOnce.Do(func() { - if e.syncer == nil { - if e.newSyncerFunc == nil { - e.syncerErr = errors.New("syncer factory is nil") - return - } - e.syncer, e.syncerErr = e.newSyncerFunc() - } - if e.syncerErr != nil { - return - } - if e.syncer == nil { - e.syncerErr = errors.New("syncer factory returned nil") - return - } - e.l1MsgReader = e.syncer - go e.syncer.Start() - }) - return e.syncerErr -} - // ============================================================================ // L2NodeV2 interface implementation for sequencer mode // ============================================================================ diff --git a/node/core/sequencers.go b/node/core/sequencers.go index 0ed154285..1323c090f 100644 --- a/node/core/sequencers.go +++ b/node/core/sequencers.go @@ -7,38 +7,10 @@ import ( "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/crypto/bls12381" "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/upgrade" ) const tmKeySize = ed25519.PubKeySize -// Keep the protected pre-cutover update path addressable for symbol-level -// audits even though all production entry points now use validatorSetAtHeight. -// The method bodies below intentionally remain unchanged apart from removing -// the old syncer-start side effect. -var _ = (*Executor).updateSequencerSet - -func cloneValidatorKeys(keys [][]byte) [][]byte { - cloned := make([][]byte, len(keys)) - for i := range keys { - cloned[i] = bytes.Clone(keys[i]) - } - return cloned -} - -// validatorSetAtHeight is the single validator data-source boundary. The -// upgrade package intentionally switches strictly after the persisted height: -// H is historical, H+1 is static. -func (e *Executor) validatorSetAtHeight(height uint64) ([][]byte, error) { - if upgrade.IsUpgraded(int64(height)) { - return cloneValidatorKeys(e.staticValidatorTmKeys), nil - } - if e.legacyValidatorSetAtHeightFunc != nil { - return e.legacyValidatorSetAtHeightFunc(int64(height)) - } - return e.getValidatorsAtHeight(int64(height)) -} - func (e *Executor) sequencerSetUpdates(height uint64) ([][]byte, error) { seqHash, err := e.sequencerCaller.SequencerSetVerifyHash(nil) if err != nil { @@ -127,7 +99,19 @@ func (e *Executor) updateSequencerSet(height uint64) ([][]byte, error) { _, isSequencer := e.seqTmKeySet[tmPKBz] if !e.isSequencer && isSequencer { - e.logger.Info("I am a sequencer") + e.logger.Info("I am a sequencer, start to launch syncer") + if e.syncer == nil { + syncer, err := e.newSyncerFunc() + if err != nil { + e.logger.Error("failed to create syncer", "error", err) + return nil, err + } + e.syncer = syncer + e.l1MsgReader = syncer // syncer works as l1MsgReader + e.syncer.Start() + } else { + go e.syncer.Start() + } } else if e.isSequencer && !isSequencer { // as the derivation always need the syncer running, it should not be stopped diff --git a/node/derivation/calldata_fixture_test.go b/node/derivation/calldata_fixture_test.go deleted file mode 100644 index 4653f515d..000000000 --- a/node/derivation/calldata_fixture_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package derivation - -import ( - "encoding/json" - "errors" - "os" - "strings" - "testing" - - "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/common/hexutil" - "github.com/stretchr/testify/require" - - "morph-l2/bindings/bindings" - "morph-l2/node/types" -) - -const targetCurrentRollupABI = `[ - {"type":"function","name":"commitBatch","stateMutability":"payable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]}],"outputs":[]}, - {"type":"function","name":"commitState","stateMutability":"nonpayable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]}],"outputs":[]}, - {"type":"function","name":"commitBatchWithProof","stateMutability":"nonpayable","inputs":[{"name":"batchDataInput","type":"tuple","components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}]},{"name":"batchHeader","type":"bytes"},{"name":"batchProof","type":"bytes"}],"outputs":[]} -]` - -type calldataFixtureCorpus struct { - SchemaVersion int `json:"schemaVersion"` - Fixtures []calldataFixture `json:"fixtures"` -} - -type calldataFixture struct { - Name string `json:"name"` - Epoch string `json:"epoch"` - Selector string `json:"selector"` - Data string `json:"data"` - Expected calldataFixtureExpected `json:"expected"` -} - -type calldataFixtureExpected struct { - Version uint64 `json:"version"` - ParentBatchHeader string `json:"parentBatchHeader"` - BlockContexts string `json:"blockContexts"` - LastBlockNumber uint64 `json:"lastBlockNumber"` - NumL1Messages uint16 `json:"numL1Messages"` - PrevStateRoot string `json:"prevStateRoot"` - PostStateRoot string `json:"postStateRoot"` - WithdrawRoot string `json:"withdrawRoot"` -} - -func loadCalldataFixtureCorpus(t *testing.T) calldataFixtureCorpus { - t.Helper() - raw, err := os.ReadFile("testdata/rollup_calldata_fixtures.json") - require.NoError(t, err) - var corpus calldataFixtureCorpus - require.NoError(t, json.Unmarshal(raw, &corpus)) - require.Equal(t, 1, corpus.SchemaVersion) - require.Len(t, corpus.Fixtures, 8) - return corpus -} - -func newFixtureDerivation(t *testing.T) *Derivation { - t.Helper() - currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) - require.NoError(t, err) - preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() - require.NoError(t, err) - legacyABI, err := types.LegacyRollupMetaData.GetAbi() - require.NoError(t, err) - beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() - require.NoError(t, err) - return &Derivation{ - rollupABI: ¤tABI, - preSubmitterRollupABI: preSubmitterABI, - legacyRollupABI: legacyABI, - beforeMoveBlockCtxABI: beforeMoveABI, - } -} - -func TestUnPackDataAllHistoricalAndCurrentSelectors(t *testing.T) { - d := newFixtureDerivation(t) - for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { - t.Run(fixture.Name, func(t *testing.T) { - data, err := hexutil.Decode(fixture.Data) - require.NoError(t, err) - require.Equal(t, fixture.Selector, hexutil.Encode(data[:4])) - - got, err := d.UnPackData(data) - require.NoError(t, err) - require.Equal(t, uint(fixture.Expected.Version), got.Version) - require.Equal(t, common.FromHex(fixture.Expected.ParentBatchHeader), []byte(got.ParentBatchHeader)) - expectedBlockContexts := fixture.Expected.BlockContexts - if expectedBlockContexts == "" { - expectedBlockContexts = "0x" - } - require.Equal(t, expectedBlockContexts, hexutil.Encode(got.BlockContexts)) - require.Equal(t, fixture.Expected.LastBlockNumber, got.LastBlockNumber) - require.Equal(t, fixture.Expected.NumL1Messages, got.NumL1Messages) - require.Equal(t, common.HexToHash(fixture.Expected.PrevStateRoot), got.PrevStateRoot) - require.Equal(t, common.HexToHash(fixture.Expected.PostStateRoot), got.PostStateRoot) - require.Equal(t, common.HexToHash(fixture.Expected.WithdrawRoot), got.WithdrawRoot) - }) - } -} - -func TestUnPackDataRejectsUnknownShortAndMalformedCalldata(t *testing.T) { - d := newFixtureDerivation(t) - for length := 0; length < 4; length++ { - _, err := d.UnPackData(make([]byte, length)) - require.ErrorIs(t, err, types.ErrNotCommitBatchTx) - } - _, err := d.UnPackData([]byte{0xde, 0xad, 0xbe, 0xef}) - require.ErrorIs(t, err, types.ErrNotCommitBatchTx) - - currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) - require.NoError(t, err) - _, err = d.UnPackData(currentABI.Methods["commitBatch"].ID) - require.Error(t, err) - require.False(t, errors.Is(err, types.ErrNotCommitBatchTx), "known selector with malformed arguments must not be reported as unknown") -} - -func TestUnPackDataMixedCutoverWindow(t *testing.T) { - d := newFixtureDerivation(t) - fixtures := make(map[string]string) - for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { - fixtures[fixture.Name] = fixture.Data - } - for _, name := range []string{ - "pre_submitter_commitBatch", - "current_commitBatch", - "pre_submitter_commitState", - "current_commitState", - "pre_submitter_commitBatchWithProof", - "current_commitBatchWithProof", - } { - data, err := hexutil.Decode(fixtures[name]) - require.NoError(t, err) - _, err = d.UnPackData(data) - require.NoError(t, err, name) - } -} - -func TestSubmissionSelectorClassification(t *testing.T) { - d := newFixtureDerivation(t) - for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { - data, err := hexutil.Decode(fixture.Data) - require.NoError(t, err) - switch fixture.Name { - case "pre_submitter_commitState", "pre_submitter_commitBatchWithProof", "current_commitState", "current_commitBatchWithProof": - require.True(t, d.isStoredSourceSubmission(data), fixture.Name) - case "current_commitBatch": - require.True(t, d.isCurrentFreshCommitBatch(data), fixture.Name) - default: - require.False(t, d.isStoredSourceSubmission(data), fixture.Name) - require.False(t, d.isCurrentFreshCommitBatch(data), fixture.Name) - } - } -} - -func TestRollupSelectorFreeze(t *testing.T) { - beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() - require.NoError(t, err) - legacyABI, err := types.LegacyRollupMetaData.GetAbi() - require.NoError(t, err) - require.Equal(t, "0x4a8d544f", hexutil.Encode(beforeMoveABI.Methods["commitBatch"].ID), "before-move selector") - require.Equal(t, "0xd63b3549", hexutil.Encode(legacyABI.Methods["commitBatch"].ID), "legacy selector") - - preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() - require.NoError(t, err) - currentABI, err := abi.JSON(strings.NewReader(targetCurrentRollupABI)) - require.NoError(t, err) - - wantOld := map[string]string{ - "commitBatch": "0x428868b5", - "commitState": "0x1e8825be", - "commitBatchWithProof": "0x4e8f1d67", - } - wantNew := map[string]string{ - "commitBatch": "0x41f756da", - "commitState": "0x67caa37a", - "commitBatchWithProof": "0x1544ba3a", - } - for name := range wantOld { - require.Equal(t, wantOld[name], hexutil.Encode(preSubmitterABI.Methods[name].ID)) - require.Equal(t, wantNew[name], hexutil.Encode(currentABI.Methods[name].ID)) - require.NotEqual(t, preSubmitterABI.Methods[name].ID, currentABI.Methods[name].ID) - } -} - -func TestGeneratedRollupBindingUsesCurrentSelectors(t *testing.T) { - generatedABI, err := bindings.RollupMetaData.GetAbi() - require.NoError(t, err) - want := map[string]string{ - "commitBatch": "0x41f756da", - "commitState": "0x67caa37a", - "commitBatchWithProof": "0x1544ba3a", - } - for name, selector := range want { - require.Equal(t, selector, hexutil.Encode(generatedABI.Methods[name].ID), name) - } -} diff --git a/node/derivation/canonical_commit.go b/node/derivation/canonical_commit.go deleted file mode 100644 index 09241d010..000000000 --- a/node/derivation/canonical_commit.go +++ /dev/null @@ -1,376 +0,0 @@ -package derivation - -import ( - "context" - "errors" - "fmt" - "math/big" - "slices" - "strings" - - "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/common" - eth "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/crypto" - geth "github.com/morph-l2/go-ethereum/eth" -) - -var ( - ErrSnapshotChanged = errors.New("fixed L1 snapshot changed") - ErrCanonicalCommitNotFound = errors.New("canonical CommitBatch log not found") - ErrStoredBlobSourceNotFound = errors.New("stored blob source not found") - ErrZeroBlobVersionedHash = errors.New("pre-cutover zero blob versioned hash") - zeroBlobVersionedHash = common.HexToHash("0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014") - canonicalResolverRollupABI = mustCanonicalResolverRollupABI() - canonicalCommitEventTopic = canonicalResolverRollupABI.Events["CommitBatch"].ID - canonicalRevertEventTopic = canonicalResolverRollupABI.Events["RevertBatch"].ID -) - -const canonicalResolverRollupABIJSON = `[ - {"type":"function","name":"committedBatches","stateMutability":"view","inputs":[{"name":"batchIndex","type":"uint256"}],"outputs":[{"name":"batchHash","type":"bytes32"}]}, - {"type":"function","name":"batchBlobVersionedHashes","stateMutability":"view","inputs":[{"name":"batchIndex","type":"uint256"}],"outputs":[{"name":"blobVersionedHash","type":"bytes32"}]}, - {"type":"event","name":"CommitBatch","anonymous":false,"inputs":[{"name":"batchIndex","type":"uint256","indexed":true},{"name":"batchHash","type":"bytes32","indexed":true}]}, - {"type":"event","name":"RevertBatch","anonymous":false,"inputs":[{"name":"batchIndex","type":"uint256","indexed":true},{"name":"batchHash","type":"bytes32","indexed":true}]} -]` - -func mustCanonicalResolverRollupABI() abi.ABI { - parsed, err := abi.JSON(strings.NewReader(canonicalResolverRollupABIJSON)) - if err != nil { - panic(err) - } - return parsed -} - -// FixedL1Snapshot pins both the number used by legacy JSON-RPC block-number -// calls and its hash. Every resolver verifies the hash before and after its -// reads, providing EIP-1898-equivalent fail-closed behavior on providers that -// do not support blockHash call options. -type FixedL1Snapshot struct { - Number uint64 - Hash common.Hash -} - -type CanonicalCommitClient interface { - HeaderByNumber(context.Context, *big.Int) (*eth.Header, error) - CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) - FilterLogs(context.Context, ethereum.FilterQuery) ([]eth.Log, error) -} - -type StoredBlobSourceClient interface { - CanonicalCommitClient - TransactionByHash(context.Context, common.Hash) (*eth.Transaction, bool, error) -} - -type CanonicalCommit struct { - BatchIndex uint64 - BatchHash common.Hash - Log eth.Log -} - -type StoredBlobSource struct { - BatchIndex uint64 - StoredHash common.Hash - CommitLog eth.Log - Tx *eth.Transaction - BlobHashes []common.Hash -} - -type RollupBatchDecoder func([]byte) (geth.RPCRollupBatch, error) - -func PinL1Snapshot(ctx context.Context, client CanonicalCommitClient, number uint64) (FixedL1Snapshot, error) { - header, err := client.HeaderByNumber(ctx, uint64Big(number)) - if err != nil { - return FixedL1Snapshot{}, err - } - if header == nil || header.Number == nil || header.Number.Uint64() != number { - return FixedL1Snapshot{}, fmt.Errorf("pin L1 snapshot %d: invalid header", number) - } - return FixedL1Snapshot{Number: number, Hash: header.Hash()}, nil -} - -func ResolveCanonicalCommit( - ctx context.Context, - client CanonicalCommitClient, - rollupAddress common.Address, - batchIndex uint64, - snapshotNumber uint64, -) (*CanonicalCommit, error) { - snapshot, err := PinL1Snapshot(ctx, client, snapshotNumber) - if err != nil { - return nil, err - } - return ResolveCanonicalCommitAtSnapshot(ctx, client, rollupAddress, batchIndex, snapshot) -} - -func ResolveCanonicalCommitAtSnapshot( - ctx context.Context, - client CanonicalCommitClient, - rollupAddress common.Address, - batchIndex uint64, - snapshot FixedL1Snapshot, -) (*CanonicalCommit, error) { - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - committedHash, err := readRollupHashAtSnapshot(ctx, client, rollupAddress, "committedBatches", batchIndex, snapshot.Number) - if err != nil { - return nil, err - } - if committedHash == (common.Hash{}) { - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - return nil, nil - } - - logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{ - FromBlock: uint64Big(0), - ToBlock: uint64Big(snapshot.Number), - Addresses: []common.Address{rollupAddress}, - Topics: [][]common.Hash{ - {canonicalCommitEventTopic, canonicalRevertEventTopic}, - {common.BigToHash(uint64Big(batchIndex))}, - }, - }) - if err != nil { - return nil, err - } - ordered, err := validateAndSortLifecycleLogs(logs, rollupAddress, batchIndex, snapshot.Number) - if err != nil { - return nil, err - } - - lastRevert := -1 - for i := range ordered { - if ordered[i].Topics[0] == canonicalRevertEventTopic { - lastRevert = i - } - } - var selected *eth.Log - for i := lastRevert + 1; i < len(ordered); i++ { - log := ordered[i] - if log.Topics[0] == canonicalCommitEventTopic && log.Topics[2] == committedHash { - candidate := log - selected = &candidate - } - } - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - if selected == nil { - return nil, fmt.Errorf("%w: batch %d, getter hash %s", ErrCanonicalCommitNotFound, batchIndex, committedHash.Hex()) - } - return &CanonicalCommit{ - BatchIndex: batchIndex, - BatchHash: committedHash, - Log: *selected, - }, nil -} - -// ResolveStoredBlobSource deliberately does not apply the canonical resolver's -// "after the last Revert" filter. Rollup retains batchBlobVersionedHashes so a -// later blobless commitState/commitBatchWithProof can reuse a blob originally -// published by a pre-Revert Commit. The source remains identified by its full -// canonical L1 log and transaction identity. -func ResolveStoredBlobSource( - ctx context.Context, - client StoredBlobSourceClient, - rollupAddress common.Address, - batchIndex uint64, - snapshotNumber uint64, - decode RollupBatchDecoder, -) (*StoredBlobSource, error) { - snapshot, err := PinL1Snapshot(ctx, client, snapshotNumber) - if err != nil { - return nil, err - } - return ResolveStoredBlobSourceAtSnapshot(ctx, client, rollupAddress, batchIndex, snapshot, decode) -} - -func ResolveStoredBlobSourceAtSnapshot( - ctx context.Context, - client StoredBlobSourceClient, - rollupAddress common.Address, - batchIndex uint64, - snapshot FixedL1Snapshot, - decode RollupBatchDecoder, -) (*StoredBlobSource, error) { - if decode == nil { - return nil, errors.New("rollup batch decoder is nil") - } - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - storedHash, err := readRollupHashAtSnapshot(ctx, client, rollupAddress, "batchBlobVersionedHashes", batchIndex, snapshot.Number) - if err != nil { - return nil, err - } - if storedHash == (common.Hash{}) || storedHash == zeroBlobVersionedHash { - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - if storedHash == zeroBlobVersionedHash { - return nil, ErrZeroBlobVersionedHash - } - return nil, fmt.Errorf("%w: batch %d has no stored hash", ErrStoredBlobSourceNotFound, batchIndex) - } - - logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{ - FromBlock: uint64Big(0), - ToBlock: uint64Big(snapshot.Number), - Addresses: []common.Address{rollupAddress}, - Topics: [][]common.Hash{ - {canonicalCommitEventTopic}, - {common.BigToHash(uint64Big(batchIndex))}, - }, - }) - if err != nil { - return nil, err - } - ordered, err := validateAndSortLifecycleLogs(logs, rollupAddress, batchIndex, snapshot.Number) - if err != nil { - return nil, err - } - - var source *StoredBlobSource - for i := len(ordered) - 1; i >= 0; i-- { - log := ordered[i] - if log.Topics[0] != canonicalCommitEventTopic { - continue - } - tx, pending, err := client.TransactionByHash(ctx, log.TxHash) - if err != nil { - return nil, err - } - if pending || tx == nil { - return nil, fmt.Errorf("stored blob source transaction %s is pending or missing", log.TxHash.Hex()) - } - if tx.Hash() != log.TxHash { - return nil, fmt.Errorf("stored blob source transaction hash mismatch: requested %s, got %s", log.TxHash.Hex(), tx.Hash().Hex()) - } - blobHashes := tx.BlobHashes() - if len(blobHashes) == 0 { - continue - } - batch, err := decode(tx.Data()) - if err != nil { - return nil, fmt.Errorf("decode stored blob source transaction %s: %w", log.TxHash.Hex(), err) - } - if !storedBlobHashMatches(batch.Version, blobHashes, storedHash) { - continue - } - source = &StoredBlobSource{ - BatchIndex: batchIndex, - StoredHash: storedHash, - CommitLog: log, - Tx: tx, - BlobHashes: slices.Clone(blobHashes), - } - break - } - if err := verifyL1Snapshot(ctx, client, snapshot); err != nil { - return nil, err - } - if source == nil { - return nil, fmt.Errorf("%w: batch %d, stored hash %s", ErrStoredBlobSourceNotFound, batchIndex, storedHash.Hex()) - } - return source, nil -} - -func storedBlobHashMatches(version uint, blobHashes []common.Hash, storedHash common.Hash) bool { - if len(blobHashes) == 0 { - return false - } - if version != 2 { - return len(blobHashes) == 1 && blobHashes[0] == storedHash - } - encoded := make([]byte, 0, len(blobHashes)*common.HashLength) - for _, hash := range blobHashes { - encoded = append(encoded, hash[:]...) - } - return crypto.Keccak256Hash(encoded) == storedHash -} - -func readRollupHashAtSnapshot( - ctx context.Context, - client CanonicalCommitClient, - rollupAddress common.Address, - method string, - batchIndex uint64, - snapshotNumber uint64, -) (common.Hash, error) { - input, err := canonicalResolverRollupABI.Pack(method, uint64Big(batchIndex)) - if err != nil { - return common.Hash{}, err - } - output, err := client.CallContract(ctx, ethereum.CallMsg{To: &rollupAddress, Data: input}, uint64Big(snapshotNumber)) - if err != nil { - return common.Hash{}, err - } - if len(output) != common.HashLength { - return common.Hash{}, fmt.Errorf("%s returned %d bytes, want %d", method, len(output), common.HashLength) - } - values, err := canonicalResolverRollupABI.Methods[method].Outputs.Unpack(output) - if err != nil { - return common.Hash{}, err - } - if len(values) != 1 { - return common.Hash{}, fmt.Errorf("%s returned %d values, want 1", method, len(values)) - } - decoded := *abi.ConvertType(values[0], new([32]byte)).(*[32]byte) - return common.Hash(decoded), nil -} - -func validateAndSortLifecycleLogs(logs []eth.Log, rollupAddress common.Address, batchIndex, snapshotNumber uint64) ([]eth.Log, error) { - indexTopic := common.BigToHash(uint64Big(batchIndex)) - ordered := slices.Clone(logs) - for i := range ordered { - log := ordered[i] - if log.Removed { - return nil, fmt.Errorf("removed lifecycle log at %d/%d/%d", log.BlockNumber, log.TxIndex, log.Index) - } - if log.Address != rollupAddress || log.BlockNumber > snapshotNumber || len(log.Topics) != 3 || log.Topics[1] != indexTopic { - return nil, fmt.Errorf("malformed lifecycle log at %d/%d/%d", log.BlockNumber, log.TxIndex, log.Index) - } - if log.Topics[0] != canonicalCommitEventTopic && log.Topics[0] != canonicalRevertEventTopic { - return nil, fmt.Errorf("unexpected lifecycle topic %s", log.Topics[0].Hex()) - } - } - slices.SortFunc(ordered, func(a, b eth.Log) int { - if a.BlockNumber != b.BlockNumber { - return compareUint64(a.BlockNumber, b.BlockNumber) - } - if a.TxIndex != b.TxIndex { - return compareUint64(uint64(a.TxIndex), uint64(b.TxIndex)) - } - return compareUint64(uint64(a.Index), uint64(b.Index)) - }) - return ordered, nil -} - -func verifyL1Snapshot(ctx context.Context, client CanonicalCommitClient, snapshot FixedL1Snapshot) error { - header, err := client.HeaderByNumber(ctx, uint64Big(snapshot.Number)) - if err != nil { - return err - } - if header == nil || header.Number == nil || header.Number.Uint64() != snapshot.Number || header.Hash() != snapshot.Hash { - return fmt.Errorf("%w: block %d expected %s", ErrSnapshotChanged, snapshot.Number, snapshot.Hash.Hex()) - } - return nil -} - -func uint64Big(value uint64) *big.Int { - return new(big.Int).SetUint64(value) -} - -func compareUint64(a, b uint64) int { - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } -} diff --git a/node/derivation/canonical_commit_test.go b/node/derivation/canonical_commit_test.go deleted file mode 100644 index d62565481..000000000 --- a/node/derivation/canonical_commit_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package derivation - -import ( - "context" - "math/big" - "testing" - - "github.com/holiman/uint256" - "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/common/hexutil" - eth "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/crypto" - "github.com/stretchr/testify/require" -) - -type resolverFakeClient struct { - header *eth.Header - changedHeader *eth.Header - changeAfterCall int - headerCalls int - callHash common.Hash - logs []eth.Log - filterCalls int - lastQuery ethereum.FilterQuery - transactions map[common.Hash]*eth.Transaction -} - -func (f *resolverFakeClient) HeaderByNumber(context.Context, *big.Int) (*eth.Header, error) { - f.headerCalls++ - if f.changedHeader != nil && f.changeAfterCall > 0 && f.headerCalls >= f.changeAfterCall { - return f.changedHeader, nil - } - return f.header, nil -} - -func (f *resolverFakeClient) CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) { - return canonicalResolverRollupABI.Methods["committedBatches"].Outputs.Pack(f.callHash) -} - -func (f *resolverFakeClient) FilterLogs(_ context.Context, query ethereum.FilterQuery) ([]eth.Log, error) { - f.filterCalls++ - f.lastQuery = query - filtered := make([]eth.Log, 0, len(f.logs)) - for _, log := range f.logs { - if len(query.Addresses) > 0 && log.Address != query.Addresses[0] { - continue - } - matched := true - for position, alternatives := range query.Topics { - if len(alternatives) == 0 { - continue - } - if len(log.Topics) <= position { - matched = false - break - } - positionMatched := false - for _, topic := range alternatives { - if log.Topics[position] == topic { - positionMatched = true - break - } - } - if !positionMatched { - matched = false - break - } - } - if matched { - filtered = append(filtered, log) - } - } - return filtered, nil -} - -func (f *resolverFakeClient) TransactionByHash(_ context.Context, hash common.Hash) (*eth.Transaction, bool, error) { - return f.transactions[hash], false, nil -} - -func resolverTestHeader(number uint64, marker byte) *eth.Header { - return ð.Header{Number: new(big.Int).SetUint64(number), Time: number, Extra: []byte{marker}} -} - -func resolverTestLog(address common.Address, event, hash common.Hash, index, block uint64, txIndex, logIndex uint) eth.Log { - return eth.Log{ - Address: address, - Topics: []common.Hash{event, common.BigToHash(uint64Big(index)), hash}, - BlockNumber: block, - TxIndex: txIndex, - Index: logIndex, - } -} - -func TestResolveCanonicalCommitAfterLastRevertWithSameHashRecommit(t *testing.T) { - const snapshotNumber = uint64(100) - const batchIndex = uint64(7) - rollupAddress := common.HexToAddress("0x1234") - batchHash := common.HexToHash("0xaaaa") - wrongHash := common.HexToHash("0xbbbb") - wantTx := common.HexToHash("0x3333") - - oldCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, batchHash, batchIndex, 10, 0, 0) - revert := resolverTestLog(rollupAddress, canonicalRevertEventTopic, batchHash, batchIndex, 11, 0, 0) - wrongCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, wrongHash, batchIndex, 12, 0, 0) - recommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, batchHash, batchIndex, 12, 1, 3) - recommit.TxHash = wantTx - client := &resolverFakeClient{ - header: resolverTestHeader(snapshotNumber, 1), - callHash: batchHash, - logs: []eth.Log{recommit, oldCommit, wrongCommit, revert}, // deliberately unsorted - } - - got, err := ResolveCanonicalCommit(context.Background(), client, rollupAddress, batchIndex, snapshotNumber) - require.NoError(t, err) - require.NotNil(t, got) - require.Equal(t, batchHash, got.BatchHash) - require.Equal(t, wantTx, got.Log.TxHash, "same-hash recommit must be identified by its post-Revert log") - require.Equal(t, snapshotNumber, client.lastQuery.ToBlock.Uint64()) - require.Equal(t, 3, client.headerCalls, "snapshot must be pinned and verified before/after reads") -} - -func TestResolveCanonicalCommitReturnsNilForZeroGetter(t *testing.T) { - client := &resolverFakeClient{header: resolverTestHeader(100, 1)} - got, err := ResolveCanonicalCommit(context.Background(), client, common.HexToAddress("0x1234"), 1, 100) - require.NoError(t, err) - require.Nil(t, got) - require.Zero(t, client.filterCalls, "zero committedBatches must not scan logs") -} - -func TestResolveCanonicalCommitRejectsChangedSnapshot(t *testing.T) { - client := &resolverFakeClient{ - header: resolverTestHeader(100, 1), - changedHeader: resolverTestHeader(100, 2), - changeAfterCall: 3, - callHash: common.HexToHash("0xaaaa"), - logs: []eth.Log{ - resolverTestLog(common.HexToAddress("0x1234"), canonicalCommitEventTopic, common.HexToHash("0xaaaa"), 1, 10, 0, 0), - }, - } - _, err := ResolveCanonicalCommit(context.Background(), client, common.HexToAddress("0x1234"), 1, 100) - require.ErrorIs(t, err, ErrSnapshotChanged) -} - -func TestResolveStoredBlobSourceSearchesBeforeRevert(t *testing.T) { - const snapshotNumber = uint64(100) - const batchIndex = uint64(7) - rollupAddress := common.HexToAddress("0x1234") - corpus := loadCalldataFixtureCorpus(t) - fixtureData := make(map[string][]byte, len(corpus.Fixtures)) - for _, fixture := range corpus.Fixtures { - data, err := hexutil.Decode(fixture.Data) - require.NoError(t, err) - fixtureData[fixture.Name] = data - } - - blobHashes := []common.Hash{common.HexToHash("0x1111"), common.HexToHash("0x2222")} - storedHashBytes := make([]byte, 0, len(blobHashes)*common.HashLength) - for _, hash := range blobHashes { - storedHashBytes = append(storedHashBytes, hash[:]...) - } - storedHash := crypto.Keccak256Hash(storedHashBytes) - originalTx := newResolverBlobTx(1, fixtureData["pre_submitter_commitBatch"], blobHashes) - bloblessTx := eth.NewTx(ð.LegacyTx{Nonce: 2, To: &rollupAddress, Data: fixtureData["current_commitState"]}) - - originalCommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, common.HexToHash("0xaaaa"), batchIndex, 10, 0, 0) - originalCommit.TxHash = originalTx.Hash() - revert := resolverTestLog(rollupAddress, canonicalRevertEventTopic, common.HexToHash("0xaaaa"), batchIndex, 11, 0, 0) - bloblessRecommit := resolverTestLog(rollupAddress, canonicalCommitEventTopic, common.HexToHash("0xbbbb"), batchIndex, 12, 0, 0) - bloblessRecommit.TxHash = bloblessTx.Hash() - client := &resolverFakeClient{ - header: resolverTestHeader(snapshotNumber, 1), - callHash: storedHash, - logs: []eth.Log{bloblessRecommit, revert, originalCommit}, - transactions: map[common.Hash]*eth.Transaction{ - originalTx.Hash(): originalTx, - bloblessTx.Hash(): bloblessTx, - }, - } - d := newFixtureDerivation(t) - - source, err := ResolveStoredBlobSource(context.Background(), client, rollupAddress, batchIndex, snapshotNumber, d.UnPackData) - require.NoError(t, err) - require.Equal(t, originalTx.Hash(), source.CommitLog.TxHash) - require.Equal(t, blobHashes, source.BlobHashes) - require.Equal(t, []common.Hash{canonicalCommitEventTopic}, client.lastQuery.Topics[0], - "stored-source lookup must scan every historical Commit and must not reuse the post-Revert canonical filter") -} - -func TestResolveStoredBlobSourcePreservesZeroHashSpecialCase(t *testing.T) { - client := &resolverFakeClient{ - header: resolverTestHeader(100, 1), - callHash: zeroBlobVersionedHash, - } - _, err := ResolveStoredBlobSource(context.Background(), client, common.HexToAddress("0x1234"), 1, 100, newFixtureDerivation(t).UnPackData) - require.ErrorIs(t, err, ErrZeroBlobVersionedHash) - require.Zero(t, client.filterCalls) -} - -func TestStoredBlobHashMatchesLegacyAndV2(t *testing.T) { - hashes := []common.Hash{common.HexToHash("0x1111"), common.HexToHash("0x2222")} - require.True(t, storedBlobHashMatches(1, hashes[:1], hashes[0])) - require.False(t, storedBlobHashMatches(1, hashes[:1], hashes[1])) - encoded := append(append([]byte{}, hashes[0][:]...), hashes[1][:]...) - require.True(t, storedBlobHashMatches(2, hashes, crypto.Keccak256Hash(encoded))) - require.False(t, storedBlobHashMatches(2, hashes, hashes[0])) -} - -func newResolverBlobTx(nonce uint64, data []byte, blobHashes []common.Hash) *eth.Transaction { - return eth.NewTx(ð.BlobTx{ - ChainID: uint256.NewInt(1), - Nonce: nonce, - GasTipCap: uint256.NewInt(1), - GasFeeCap: uint256.NewInt(2), - Gas: 100_000, - To: common.HexToAddress("0x1234"), - Value: uint256.NewInt(0), - Data: data, - BlobFeeCap: uint256.NewInt(1), - BlobHashes: blobHashes, - V: uint256.NewInt(0), - R: uint256.NewInt(0), - S: uint256.NewInt(0), - }) -} diff --git a/node/derivation/config.go b/node/derivation/config.go index 441a1e697..a3f194ba8 100644 --- a/node/derivation/config.go +++ b/node/derivation/config.go @@ -179,6 +179,11 @@ func (c *Config) SetCliContext(ctx *cli.Context) error { } } + legacyValidatorMode := ctx.GlobalBool(flags.LegacyValidatorMode.Name) + if legacyValidatorMode { + log.Warn("--validator is deprecated; use --derivation.verify-mode=layer1") + c.VerifyMode = VerifyModeLayer1 + } if ctx.GlobalIsSet(flags.DerivationVerifyMode.Name) { c.VerifyMode = ctx.GlobalString(flags.DerivationVerifyMode.Name) } diff --git a/node/derivation/config_test.go b/node/derivation/config_test.go index b72819bc7..4148c0c96 100644 --- a/node/derivation/config_test.go +++ b/node/derivation/config_test.go @@ -42,6 +42,31 @@ func TestVerifyMode_AcceptsExplicitModes(t *testing.T) { } } +func TestVerifyMode_LegacyValidatorAlias(t *testing.T) { + cfg := DefaultConfig() + if err := cfg.SetCliContext(newVerifyModeTestContext(t, map[string]string{ + flags.LegacyValidatorMode.Name: "true", + })); err != nil { + t.Fatalf("legacy validator alias rejected: %v", err) + } + if cfg.VerifyMode != VerifyModeLayer1 { + t.Fatalf("legacy validator alias resolved to %q, want %q", cfg.VerifyMode, VerifyModeLayer1) + } +} + +func TestVerifyMode_ExplicitModeOverridesLegacyValidatorAlias(t *testing.T) { + cfg := DefaultConfig() + if err := cfg.SetCliContext(newVerifyModeTestContext(t, map[string]string{ + flags.LegacyValidatorMode.Name: "true", + flags.DerivationVerifyMode.Name: VerifyModeLocal, + })); err != nil { + t.Fatalf("explicit verify-mode rejected: %v", err) + } + if cfg.VerifyMode != VerifyModeLocal { + t.Fatalf("explicit verify-mode resolved to %q, want %q", cfg.VerifyMode, VerifyModeLocal) + } +} + func TestVerifyMode_RejectsUnknown(t *testing.T) { // "hybrid" was the old default; ensure post-removal it's rejected so // stale operator configs fail loud rather than silently falling back to @@ -125,6 +150,7 @@ func newVerifyModeTestContext(t *testing.T, values map[string]string) *cli.Conte flagSet := flag.NewFlagSet(t.Name(), flag.ContinueOnError) for _, f := range []cli.Flag{ + flags.LegacyValidatorMode, flags.DerivationVerifyMode, flags.MetricsPort, flags.L1BeaconAddr, diff --git a/node/derivation/derivation.go b/node/derivation/derivation.go index c2dab2f08..b050f3483 100644 --- a/node/derivation/derivation.go +++ b/node/derivation/derivation.go @@ -24,7 +24,6 @@ import ( "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" - commonbatch "morph-l2/common/batch" nodecommon "morph-l2/node/common" "morph-l2/node/sync" "morph-l2/node/types" @@ -50,7 +49,6 @@ type Derivation struct { L2ToL1MessagePasser *bindings.L2ToL1MessagePasser rollupABI *abi.ABI - preSubmitterRollupABI *abi.ABI legacyRollupABI *abi.ABI // before remove skipMap beforeMoveBlockCtxABI *abi.ABI @@ -114,10 +112,6 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, if err != nil { return nil, err } - preSubmitterRollupAbi, err := types.PreSubmitterRollupMetaData.GetAbi() - if err != nil { - return nil, err - } beforeMoveBlockCtxAbi, err := types.BeforeMoveBlockCtxABI.GetAbi() if err != nil { return nil, err @@ -141,7 +135,6 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, syncer: syncer, rollup: rollup, rollupABI: rollupAbi, - preSubmitterRollupABI: preSubmitterRollupAbi, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxAbi, logger: logger, @@ -316,10 +309,6 @@ func (d *Derivation) derivationBlock(ctx context.Context) { d.logger.Error("fetch batch info outline failed", "err", err) return } - if err := d.hydrateStoredBlobHashes(ctx, batchInfo, lg.TxHash, lg.BlockNumber); err != nil { - d.logger.Error("resolve stored blob source failed", "batchIndex", batchInfo.batchIndex, "err", err) - return - } d.logger.Info("local verify fetched batch metadata", "batchIndex", batchInfo.batchIndex, "version", batchInfo.version, @@ -563,63 +552,30 @@ func (d *Derivation) fetchRollupDataByTxHash(txHash common.Hash, blockNumber uin return nil, err } + // Get block header to retrieve timestamp + header, err := d.l1Client.HeaderByNumber(d.ctx, big.NewInt(int64(blockNumber))) + if err != nil { + return nil, err + } + // Get transaction blob hashes blobHashes := tx.BlobHashes() - blobSourceTx := tx - blobSourceBlockNumber := blockNumber - if len(blobHashes) == 0 && d.isCurrentFreshCommitBatch(tx.Data()) { - return nil, fmt.Errorf("current commitBatch %s has no fresh blob", txHash.Hex()) - } - if len(blobHashes) == 0 && d.isStoredSourceSubmission(tx.Data()) { - parentBatchIndex, indexErr := commonbatch.BatchHeaderBytes(batch.ParentBatchHeader).BatchIndex() - if indexErr != nil { - return nil, fmt.Errorf("resolve stored blob source batch index: %w", indexErr) - } - source, sourceErr := ResolveStoredBlobSource( - d.ctx, - d.l1Client, - d.RollupContractAddress, - parentBatchIndex+1, - blockNumber, - d.UnPackData, - ) - if sourceErr != nil && !errors.Is(sourceErr, ErrZeroBlobVersionedHash) { - return nil, sourceErr - } - if source != nil { - blobSourceTx = source.Tx - blobSourceBlockNumber = source.CommitLog.BlockNumber - blobHashes = source.BlobHashes - d.logger.Info("recovered stored blob source", - "batchIndex", parentBatchIndex+1, - "commitTxHash", txHash, - "sourceTxHash", source.CommitLog.TxHash, - "sourceBlockNumber", source.CommitLog.BlockNumber) - } - } if len(blobHashes) > 0 { - d.logger.Info("Transaction contains blobs", "txHash", blobSourceTx.Hash(), "blobCount", len(blobHashes)) - - // Retrieve the timestamp and blob index positions from the transaction - // that actually published the blobs, not from a later blobless commit. - header, err := d.l1Client.HeaderByNumber(d.ctx, big.NewInt(int64(blobSourceBlockNumber))) - if err != nil { - return nil, err - } + d.logger.Info("Transaction contains blobs", "txHash", txHash, "blobCount", len(blobHashes)) // Initialize indexedBlobHashes as nil var indexedBlobHashes []IndexedBlobHash // Only try to build IndexedBlobHash array if not forcing get all blobs // Try to get the block to build IndexedBlobHash array - block, err := d.l1Client.BlockByNumber(d.ctx, big.NewInt(int64(blobSourceBlockNumber))) + block, err := d.l1Client.BlockByNumber(d.ctx, big.NewInt(int64(blockNumber))) if err == nil { // Successfully got the block, now build IndexedBlobHash array - d.logger.Info("Building IndexedBlobHash array from block", "blockNumber", blobSourceBlockNumber) - indexedBlobHashes = dataAndHashesFromTxs(block.Transactions(), blobSourceTx) + d.logger.Info("Building IndexedBlobHash array from block", "blockNumber", blockNumber) + indexedBlobHashes = dataAndHashesFromTxs(block.Transactions(), tx) d.logger.Info("Built IndexedBlobHash array", "count", len(indexedBlobHashes)) } else { - d.logger.Info("Failed to get block, will try fetching all blobs", "blockNumber", blobSourceBlockNumber, "error", err) + d.logger.Info("Failed to get block, will try fetching all blobs", "blockNumber", blockNumber, "error", err) } // Get all blobs corresponding to this timestamp, content-verified @@ -643,86 +599,25 @@ func (d *Derivation) fetchRollupDataByTxHash(txHash common.Hash, blockNumber uin rollupData.l1BlockNumber = blockNumber rollupData.txHash = txHash rollupData.nonce = tx.Nonce() - rollupData.blobHashes = blobHashes + rollupData.blobHashes = tx.BlobHashes() return rollupData, nil } -func (d *Derivation) hydrateStoredBlobHashes(ctx context.Context, batchInfo *BatchInfo, txHash common.Hash, blockNumber uint64) error { - if batchInfo == nil || len(batchInfo.blobHashes) > 0 { - return nil - } - tx, pending, err := d.l1Client.TransactionByHash(ctx, txHash) - if err != nil { - return err - } - if pending || tx == nil { - return errors.New("pending or missing rollup transaction") - } - if d.isCurrentFreshCommitBatch(tx.Data()) { - return fmt.Errorf("current commitBatch %s has no fresh blob", txHash.Hex()) - } - if !d.isStoredSourceSubmission(tx.Data()) { - return nil - } - source, err := ResolveStoredBlobSource( - ctx, - d.l1Client, - d.RollupContractAddress, - batchInfo.batchIndex, - blockNumber, - d.UnPackData, - ) - if errors.Is(err, ErrZeroBlobVersionedHash) { - return nil // frozen pre-cutover ZERO_VERSIONED_HASH branch - } - if err != nil { - return err - } - batchInfo.blobHashes = source.BlobHashes - return nil -} - -func (d *Derivation) isStoredSourceSubmission(data []byte) bool { - return matchesRollupMethodSelector(d.preSubmitterRollupABI, data, "commitState", "commitBatchWithProof") || - matchesRollupMethodSelector(d.rollupABI, data, "commitState", "commitBatchWithProof") -} - -func (d *Derivation) isCurrentFreshCommitBatch(data []byte) bool { - if !matchesRollupMethodSelector(d.rollupABI, data, "commitBatch") { - return false - } - // Until bindings are regenerated in a mixed development checkout, the - // current and frozen ABI may temporarily have the same old selector. Never - // reinterpret that frozen historical selector as the fresh-blob-only call. - return !matchesRollupMethodSelector(d.preSubmitterRollupABI, data, "commitBatch") -} - -func matchesRollupMethodSelector(contractABI *abi.ABI, data []byte, methodNames ...string) bool { - if contractABI == nil || len(data) < 4 { - return false - } - for _, name := range methodNames { - if method, ok := contractABI.Methods[name]; ok && bytes.Equal(method.ID, data[:4]) { - return true - } - } - return false -} - func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { var batch geth.RPCRollupBatch - if len(data) < 4 { - return batch, types.ErrNotCommitBatchTx - } if bytes.Equal(d.beforeMoveBlockCtxABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.beforeMoveBlockCtxABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { return batch, fmt.Errorf("submitBatches Unpack error:%v", err) } - if len(args) == 0 { - return batch, errors.New("commitBatch has no batchDataInput") - } - rollupBatchData := *abi.ConvertType(args[0], new(beforeMoveBatchDataInput)).(*beforeMoveBatchDataInput) + rollupBatchData := args[0].(struct { + Version uint8 "json:\"version\"" + ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" + BlockContexts []uint8 "json:\"blockContexts\"" + PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" + PostStateRoot [32]uint8 "json:\"postStateRoot\"" + WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" + }) batch = geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, @@ -731,16 +626,20 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } - return batch, nil } else if bytes.Equal(d.legacyRollupABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.legacyRollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { return batch, fmt.Errorf("submitBatches Unpack error:%v", err) } - if len(args) == 0 { - return batch, errors.New("commitBatch has no batchDataInput") - } - rollupBatchData := *abi.ConvertType(args[0], new(legacyBatchDataInput)).(*legacyBatchDataInput) + rollupBatchData := args[0].(struct { + Version uint8 "json:\"version\"" + ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" + BlockContexts []uint8 "json:\"blockContexts\"" + SkippedL1MessageBitmap []uint8 "json:\"skippedL1MessageBitmap\"" + PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" + PostStateRoot [32]uint8 "json:\"postStateRoot\"" + WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" + }) batch = geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, @@ -749,66 +648,44 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } - return batch, nil - } else if decoded, matched, err := unpackModernRollupCall(d.preSubmitterRollupABI, data); matched { - return decoded, err - } else if decoded, matched, err := unpackModernRollupCall(d.rollupABI, data); matched { - return decoded, err - } - return batch, types.ErrNotCommitBatchTx -} - -type beforeMoveBatchDataInput struct { - Version uint8 - ParentBatchHeader []byte - BlockContexts []byte - PrevStateRoot [32]byte - PostStateRoot [32]byte - WithdrawalRoot [32]byte -} - -type legacyBatchDataInput struct { - Version uint8 - ParentBatchHeader []byte - BlockContexts []byte - SkippedL1MessageBitmap []byte - PrevStateRoot [32]byte - PostStateRoot [32]byte - WithdrawalRoot [32]byte -} - -type modernBatchDataInput struct { - Version uint8 - ParentBatchHeader []byte - LastBlockNumber uint64 - NumL1Messages uint16 - PrevStateRoot [32]byte - PostStateRoot [32]byte - WithdrawalRoot [32]byte -} - -// unpackModernRollupCall recognizes all three modern submission entrypoints. -// Pre-submitter and current ABIs are passed separately so their selectors stay -// independently frozen; only args[0] (BatchDataInput) is consumed. -func unpackModernRollupCall(contractABI *abi.ABI, data []byte) (geth.RPCRollupBatch, bool, error) { - var batch geth.RPCRollupBatch - if contractABI == nil || len(data) < 4 { - return batch, false, nil - } - for _, methodName := range []string{"commitBatch", "commitState", "commitBatchWithProof"} { - method, ok := contractABI.Methods[methodName] - if !ok || !bytes.Equal(method.ID, data[:4]) { - continue - } - args, err := method.Inputs.Unpack(data[4:]) + } else if bytes.Equal(d.rollupABI.Methods["commitBatch"].ID, data[:4]) { + args, err := d.rollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { - return batch, true, fmt.Errorf("%s Unpack error:%v", methodName, err) + return batch, fmt.Errorf("submitBatches Unpack error:%v", err) } - if len(args) == 0 { - return batch, true, fmt.Errorf("%s has no batchDataInput", methodName) + rollupBatchData := args[0].(struct { + Version uint8 "json:\"version\"" + ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" + LastBlockNumber uint64 "json:\"lastBlockNumber\"" + NumL1Messages uint16 "json:\"numL1Messages\"" + PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" + PostStateRoot [32]uint8 "json:\"postStateRoot\"" + WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" + }) + batch = geth.RPCRollupBatch{ + Version: uint(rollupBatchData.Version), + ParentBatchHeader: rollupBatchData.ParentBatchHeader, + LastBlockNumber: rollupBatchData.LastBlockNumber, + NumL1Messages: rollupBatchData.NumL1Messages, + PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), + PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), + WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } - rollupBatchData := *abi.ConvertType(args[0], new(modernBatchDataInput)).(*modernBatchDataInput) - return geth.RPCRollupBatch{ + } else if bytes.Equal(d.rollupABI.Methods["commitBatchWithProof"].ID, data[:4]) { + args, err := d.rollupABI.Methods["commitBatchWithProof"].Inputs.Unpack(data[4:]) + if err != nil { + return batch, fmt.Errorf("commitBatchWithProof Unpack error:%v", err) + } + rollupBatchData := args[0].(struct { + Version uint8 "json:\"version\"" + ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" + LastBlockNumber uint64 "json:\"lastBlockNumber\"" + NumL1Messages uint16 "json:\"numL1Messages\"" + PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" + PostStateRoot [32]uint8 "json:\"postStateRoot\"" + WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" + }) + batch = geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, LastBlockNumber: rollupBatchData.LastBlockNumber, @@ -816,9 +693,11 @@ func unpackModernRollupCall(contractABI *abi.ABI, data []byte) (geth.RPCRollupBa PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), - }, true, nil + } + } else { + return batch, types.ErrNotCommitBatchTx } - return batch, false, nil + return batch, nil } func (d *Derivation) parseBatch(batch geth.RPCRollupBatch) (*BatchInfo, error) { diff --git a/node/derivation/derivation_test.go b/node/derivation/derivation_test.go index d70b88d99..69eb750d6 100644 --- a/node/derivation/derivation_test.go +++ b/node/derivation/derivation_test.go @@ -21,13 +21,10 @@ func TestUnPackData(t *testing.T) { require.NoError(t, err) legacyRollupAbi, err := types.LegacyRollupMetaData.GetAbi() require.NoError(t, err) - preSubmitterRollupABI, err := types.PreSubmitterRollupMetaData.GetAbi() - require.NoError(t, err) beforeMoveBlockCtxABI, err := types.BeforeMoveBlockCtxABI.GetAbi() require.NoError(t, err) d := Derivation{ rollupABI: rollupAbi, - preSubmitterRollupABI: preSubmitterRollupABI, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxABI, } diff --git a/node/derivation/testdata/rollup_calldata_fixtures.json b/node/derivation/testdata/rollup_calldata_fixtures.json deleted file mode 100644 index b728a2023..000000000 --- a/node/derivation/testdata/rollup_calldata_fixtures.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "schemaVersion": 1, - "fixtures": [ - { - "name": "before_move_commitBatch", - "epoch": "before-move", - "selector": "0x4a8d544f", - "data": "0x4a8d544f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 0, - "parentBatchHeader": "0x010203", - "blockContexts": "0xaabb", - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "legacy_commitBatch", - "epoch": "legacy", - "selector": "0xd63b3549", - "data": "0xd63b3549000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 1, - "parentBatchHeader": "0x010203", - "blockContexts": "0xaabb", - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "pre_submitter_commitBatch", - "epoch": "pre-submitter", - "selector": "0x428868b5", - "data": "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "pre_submitter_commitState", - "epoch": "pre-submitter", - "selector": "0x1e8825be", - "data": "0x1e8825be00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "pre_submitter_commitBatchWithProof", - "epoch": "pre-submitter", - "selector": "0x4e8f1d67", - "data": "0x4e8f1d67000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "current_commitBatch", - "epoch": "current", - "selector": "0x41f756da", - "data": "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "current_commitState", - "epoch": "current", - "selector": "0x67caa37a", - "data": "0x67caa37a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - }, - { - "name": "current_commitBatchWithProof", - "epoch": "current", - "selector": "0x1544ba3a", - "data": "0x1544ba3a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", - "expected": { - "version": 2, - "parentBatchHeader": "0x010203", - "lastBlockNumber": 12345, - "numL1Messages": 7, - "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", - "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", - "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" - } - } - ] -} diff --git a/node/flags/flags.go b/node/flags/flags.go index 6d7277ab1..e6ed45f78 100644 --- a/node/flags/flags.go +++ b/node/flags/flags.go @@ -144,10 +144,10 @@ var ( EnvVar: prefixEnvVar("TDM_CONFIG"), } - StaticValidatorTmKeys = cli.StringSliceFlag{ - Name: "static-validator-tm-key", - Usage: "Tendermint ed25519 validator public key (32-byte hex); repeat for every network validator", - EnvVar: prefixEnvVar("STATIC_VALIDATOR_TM_KEYS"), + DevSequencer = &cli.BoolFlag{ + Name: "dev-sequencer", + Usage: "explicitly specify that running as a sequencer. If it enables, the tendermint validator/batch params won't be changed no matter what happens to staking/gov contacts. Only use in dev/test mode", + EnvVar: prefixEnvVar("DEV_SEQUENCER"), } MockEnabled = &cli.BoolFlag{ @@ -156,6 +156,12 @@ var ( EnvVar: prefixEnvVar("MOCK_SEQUENCER"), } + LegacyValidatorMode = cli.BoolFlag{ + Name: "validator", + Usage: "Deprecated compatibility alias for --derivation.verify-mode=layer1", + EnvVar: prefixEnvVar("VALIDATOR"), + } + // derivation RollupContractAddress = cli.StringFlag{ Name: "derivation.rollupAddress", @@ -395,9 +401,10 @@ var Flags = []cli.Flag{ DBCache, DBFreezer, - StaticValidatorTmKeys, + DevSequencer, TendermintConfigPath, MockEnabled, + LegacyValidatorMode, // derivation RollupContractAddress, diff --git a/node/go.mod b/node/go.mod index 2b127d3aa..fd46c9d89 100644 --- a/node/go.mod +++ b/node/go.mod @@ -12,7 +12,6 @@ require ( github.com/hashicorp/golang-lru v1.0.2 github.com/hashicorp/raft v1.7.3 github.com/hashicorp/raft-boltdb/v2 v2.3.1 - github.com/holiman/uint256 v1.2.4 github.com/mdlayher/vsock v1.2.1 github.com/morph-l2/go-ethereum v1.10.14-0.20260810084402-5a13ad4d76fe github.com/pkg/errors v0.9.1 @@ -74,6 +73,7 @@ require ( github.com/hashicorp/go-uuid v1.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iden3/go-iden3-crypto v0.0.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/node/ops-morph/docker-compose.yml b/node/ops-morph/docker-compose.yml index 0ca681209..4f9106aad 100644 --- a/node/ops-morph/docker-compose.yml +++ b/node/ops-morph/docker-compose.yml @@ -49,7 +49,7 @@ services: - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} + --dev-sequencer --home $NODE_DATA_DIR tx-submitter: @@ -70,4 +70,4 @@ services: - TX_SUBMITTER_BATCH_BLOCK_NUM=1 - TX_SUBMITTER_BATCH_NUM=1 - TX_SUBMITTER_FIRST_TIME=true - - TX_SUBMITTER_CHAIN_ID=900 + - TX_SUBMITTER_CHAIN_ID=900 \ No newline at end of file diff --git a/node/ops-morph/testnet/docker-compose.yml b/node/ops-morph/testnet/docker-compose.yml index b58418c1e..d0322fb09 100644 --- a/node/ops-morph/testnet/docker-compose.yml +++ b/node/ops-morph/testnet/docker-compose.yml @@ -129,7 +129,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} + --dev-sequencer --home $NODE_DATA_DIR node-1: @@ -153,7 +153,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} + --dev-sequencer --home $NODE_DATA_DIR node-2: @@ -177,7 +177,7 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} + --dev-sequencer --home $NODE_DATA_DIR node-3: @@ -201,5 +201,5 @@ services: - "${PWD}/../jwt-secret.txt:${JWT_SECRET_PATH}" command: > morphnode - --static-validator-tm-key ${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} + --dev-sequencer --home $NODE_DATA_DIR diff --git a/node/ops-morph/testnet/launch.sh b/node/ops-morph/testnet/launch.sh index dff9c4f85..3394279ec 100644 --- a/node/ops-morph/testnet/launch.sh +++ b/node/ops-morph/testnet/launch.sh @@ -3,9 +3,8 @@ export MORPH_NODE_L2_ENGINE_AUTH=ops-morph/jwt-secret.txt export MORPH_NODE_L1_ETH_RPC=https://eth-goerli.g.alchemy.com/v2/hmGN_z77oy7LlFgPivFuKF893Iog5AOV export MORPH_NODE_SYNC_DEPOSIT_CONTRACT_ADDRESS=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 -: "${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?set the comma-separated network Tendermint ed25519 public keys}" -nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node0 --l2.eth=http://127.0.0.1:8545 --l2.engine=http://127.0.0.1:8551 > ./mytestnet/node0.log 2>&1 & -nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node1 --l2.eth=http://127.0.0.1:8645 --l2.engine=http://127.0.0.1:8651 > ./mytestnet/node1.log 2>&1 & -nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node2 --l2.eth=http://127.0.0.1:8745 --l2.engine=http://127.0.0.1:8751 > ./mytestnet/node2.log 2>&1 & -nohup ./build/bin/morphnode --static-validator-tm-key "$MORPH_NODE_STATIC_VALIDATOR_TM_KEYS" --home ./mytestnet/node3 --l2.eth=http://127.0.0.1:8845 --l2.engine=http://127.0.0.1:8851 > ./mytestnet/node3.log 2>&1 & +nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node0 --l2.eth=http://127.0.0.1:8545 --l2.engine=http://127.0.0.1:8551 > ./mytestnet/node0.log 2>&1 & +nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node1 --l2.eth=http://127.0.0.1:8645 --l2.engine=http://127.0.0.1:8651 > ./mytestnet/node1.log 2>&1 & +nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node2 --l2.eth=http://127.0.0.1:8745 --l2.engine=http://127.0.0.1:8751 > ./mytestnet/node2.log 2>&1 & +nohup ./build/bin/morphnode --dev-sequencer --home ./mytestnet/node3 --l2.eth=http://127.0.0.1:8845 --l2.engine=http://127.0.0.1:8851 > ./mytestnet/node3.log 2>&1 & \ No newline at end of file diff --git a/node/types/abi/pre_submitter_rollup.json b/node/types/abi/pre_submitter_rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/node/types/abi/pre_submitter_rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/node/types/batch.go b/node/types/batch.go index a7785a19f..3038dbb74 100644 --- a/node/types/batch.go +++ b/node/types/batch.go @@ -1,20 +1,10 @@ package types import ( - _ "embed" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" ) -//go:embed abi/pre_submitter_rollup.json -var preSubmitterRollupABI string - var ( - // PreSubmitterRollupMetaData is the immutable production ABI immediately - // before BatchSignatureInput was removed. Historical calldata decoding must - // never be coupled to the regenerated current Rollup binding. - PreSubmitterRollupMetaData = &bind.MetaData{ABI: preSubmitterRollupABI} - LegacyRollupMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorIncorrectBatchLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorNoBlockInBatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"blockContexts\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", } diff --git a/ops/devnet-morph/devnet/__init__.py b/ops/devnet-morph/devnet/__init__.py index a226e20c5..020efb254 100644 --- a/ops/devnet-morph/devnet/__init__.py +++ b/ops/devnet-morph/devnet/__init__.py @@ -1,6 +1,4 @@ import argparse -import base64 -import binascii import logging import os import subprocess @@ -46,24 +44,6 @@ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', ), help='Private key for the L1 contract deployer/owner') -parser.add_argument('--batch-submitter-private-key', - default=os.environ.get( - 'BATCH_SUBMITTER_PRIVATE_KEY', - '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', - ), - help='Independent private key used by the devnet batch submitter') -parser.add_argument('--batch-submitter-address', - default=os.environ.get( - 'BATCH_SUBMITTER_ADDRESS', - '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', - ), - help='Address expected to match --batch-submitter-private-key') -parser.add_argument('--legacy-genesis-l1-staking-proxy', - default=os.environ.get( - 'LEGACY_GENESIS_L1_STAKING_PROXY', - '0x000000000000000000000000000000000000dEaD', - ), - help='Immutable-only legacy OTHER_STAKING fixture; never used as Submitter') parser.add_argument('--cluster', action="store_true", default=os.environ.get('DEVNET_CLUSTER', '').lower() in ('1', 'true', 'yes'), help='Start an HA sequencer cluster instead of making node-0 the sequencer') @@ -216,10 +196,6 @@ def devnet_deploy(paths, args): deploy_config = read_json(devnet_cfg_orig) deploy_config['l1GenesisBlockTimestamp'] = "0x{:x}".format(int(time.time())) deploy_config['l1StartingBlockTag'] = 'earliest' - # The current L2 genesis format still has the historical OTHER_STAKING - # immutable. Keep that fixture explicit and separate from the live - # Submitter address; it must never be renamed or repointed to Submitter. - deploy_config['l1StakingProxy'] = args.legacy_genesis_l1_staking_proxy temp_deploy_config = pjoin(paths.devnet_dir, 'deploy-config.json') write_json(temp_deploy_config, deploy_config) @@ -276,46 +252,29 @@ def devnet_deploy(paths, args): log.info('Parser L1 contracts...') addresses = {} - deployment_blocks = {} deployment = read_json(paths.deployment_dir) for d in deployment: addresses[d['name']] = d['address'] - deployment_blocks[d['name']] = int(d['number']) log.info('Passing L1 contracts address:', addresses) - rollup_deployed_block = deployment_blocks.get('Proxy__Rollup', 0) - if rollup_deployed_block <= 0: - raise RuntimeError('Proxy__Rollup deployment block missing from deployment output') - - log.info('Registering and funding the independent batch submitter...') - submitter_proxy = addresses['Proxy__Submitter'] - if submitter_proxy.lower() == args.legacy_genesis_l1_staking_proxy.lower(): - raise RuntimeError( - 'live Proxy__Submitter must differ from immutable legacy L1 staking fixture' - ) - submitter_address = run_command_capture_output([ - 'cast', 'wallet', 'address', '--private-key', args.batch_submitter_private_key, - ], cwd=paths.contracts_dir).stdout.strip() - if submitter_address.lower() != args.batch_submitter_address.lower(): - raise RuntimeError( - f'batch submitter key resolves to {submitter_address}, expected {args.batch_submitter_address}' - ) - run_command([ - 'cast', 'send', submitter_proxy, 'addSubmitter(address)', submitter_address, - '--rpc-url', 'http://127.0.0.1:9545', - '--private-key', args.deployer_private_key, - ], cwd=paths.contracts_dir) - run_command([ - 'cast', 'send', submitter_proxy, 'stake()', - '--rpc-url', 'http://127.0.0.1:9545', - '--value', '1ether', - '--private-key', args.batch_submitter_private_key, - ], cwd=paths.contracts_dir) + log.info('Do Staking Sequencer...') + deploy_config['l2StakingAddresses'] + deploy_config['l2StakingPks'] + deploy_config['l2StakingTmKeys'] + deploy_config['l2StakingBlsKeys'] + for i in range(4): + run_command(['cast', 'send', addresses['Proxy__L1Staking'], + 'register(bytes32,bytes memory)', + deploy_config['l2StakingTmKeys'][i], + deploy_config['l2StakingBlsKeys'][i], + '--rpc-url', 'http://127.0.0.1:9545', + '--value', '1ether', + '--private-key', deploy_config['l2StakingPks'][i] + ]) configure_l1_sequencer(paths, args, addresses, deploy_config) sequencer_upgrade_time = int((time.time() + args.sequencer_upgrade_offset_seconds) * 1000) active_sequencer_private_key = '' if args.cluster else args.sequencer_private_key - static_validator_tm_keys = read_static_validator_tm_keys(paths.ops_dir) log.info( f'Single sequencer mode enabled: sequencer={args.sequencer_address}, cluster={args.cluster}, ' f'upgrade_time_ms={sequencer_upgrade_time}, ' @@ -334,25 +293,17 @@ def devnet_deploy(paths, args): if line and not line.startswith('#'): key, value = line.split('=') env_data[key.strip()] = value.strip() - # Never carry the retired runtime authority forward from an older - # tracked/local .env. The only allowed legacy staking address is the - # explicit immutable genesis fixture above. - env_data.pop('Proxy__L1Staking', None) - env_data.pop('MORPH_L1STAKING', None) env_data['L1_CROSS_DOMAIN_MESSENGER'] = addresses['Proxy__L1CrossDomainMessenger'] env_data['MORPH_PORTAL'] = addresses['Proxy__L1MessageQueueWithGasPriceOracle'] env_data['MORPH_ROLLUP'] = addresses['Proxy__Rollup'] - env_data['MORPH_ROLLUP_DEPLOY_BLOCK'] = str(rollup_deployed_block) env_data['RUST_LOG'] = rust_log_level - env_data['Proxy__Submitter'] = submitter_proxy - env_data['MORPH_SUBMITTER'] = submitter_proxy + env_data['Proxy__L1Staking'] = addresses['Proxy__L1Staking'] + env_data['MORPH_L1STAKING'] = addresses['Proxy__L1Staking'] env_data['L1_SEQUENCER_CONTRACT'] = addresses.get('Proxy__L1Sequencer', '') env_data['SEQUENCER_PRIVATE_KEY'] = args.sequencer_private_key env_data['ACTIVE_SEQUENCER_PRIVATE_KEY'] = active_sequencer_private_key env_data['HA_SEQUENCER_ADDR'] = args.sequencer_address env_data['SEQUENCER_UPGRADE_TIME'] = str(sequencer_upgrade_time) - env_data['MORPH_NODE_STATIC_VALIDATOR_TM_KEYS'] = static_validator_tm_keys - env_data['BATCH_SUBMITTER_PRIVATE_KEY'] = args.batch_submitter_private_key envfile.seek(0) for key, value in env_data.items(): envfile.write(f'{key}={value}\n') @@ -367,9 +318,7 @@ def devnet_deploy(paths, args): env={ 'MORPH_PORTAL': addresses['Proxy__L1MessageQueueWithGasPriceOracle'], 'MORPH_ROLLUP': addresses['Proxy__Rollup'], - 'MORPH_ROLLUP_DEPLOY_BLOCK': str(rollup_deployed_block), - 'MORPH_SUBMITTER': submitter_proxy, - 'BATCH_SUBMITTER_PRIVATE_KEY': args.batch_submitter_private_key, + 'MORPH_L1STAKING': addresses['Proxy__L1Staking'], 'PWD': paths.ops_dir, 'NODE_DATA_DIR': '/data', 'GETH_DATA_DIR': '/db', @@ -380,26 +329,11 @@ def devnet_deploy(paths, args): 'SEQUENCER_PRIVATE_KEY': args.sequencer_private_key, 'ACTIVE_SEQUENCER_PRIVATE_KEY': active_sequencer_private_key, 'SEQUENCER_UPGRADE_TIME': str(sequencer_upgrade_time), - 'MORPH_NODE_STATIC_VALIDATOR_TM_KEYS': static_validator_tm_keys, }) wait_up(8545) wait_for_rpc_server('127.0.0.1:8545') -def read_static_validator_tm_keys(ops_dir): - """Load and validate the devnet's canonical Tendermint ed25519 public key.""" - key_path = pjoin(ops_dir, 'node0', 'priv_validator_key.json') - with open(key_path, 'r', encoding='utf-8') as key_file: - encoded = json.load(key_file)['pub_key']['value'] - try: - key = base64.b64decode(encoded, validate=True) - except (ValueError, binascii.Error) as error: - raise RuntimeError(f'invalid Tendermint validator public key in {key_path}') from error - if len(key) != 32: - raise RuntimeError(f'Tendermint validator public key in {key_path} must be 32 bytes') - return key.hex() - - def configure_l1_sequencer(paths, args, addresses, deploy_config): """Register the devnet's single sequencer in L1Sequencer before starting L2.""" l1_sequencer_addr = addresses.get('Proxy__L1Sequencer', '') diff --git a/ops/devnet-morph/tests/test_devnet_config.py b/ops/devnet-morph/tests/test_devnet_config.py index fa616d047..f64532279 100644 --- a/ops/devnet-morph/tests/test_devnet_config.py +++ b/ops/devnet-morph/tests/test_devnet_config.py @@ -92,42 +92,6 @@ def test_compose_file_args_can_enable_cluster_mode(self): ], ) - def test_centralized_runtime_uses_submitter_and_static_validator_inputs(self): - compose = (DOCKER_DIR / "docker-compose-devnet.yml").read_text() - env_file = (DOCKER_DIR / ".env").read_text() - devnet_source = (DEVNET_PACKAGE / "devnet" / "__init__.py").read_text() - - self.assertNotIn("Proxy__L1Staking=", env_file) - self.assertNotIn("MORPH_L1STAKING=", env_file) - self.assertIn("MORPH_SUBMITTER=", env_file) - self.assertIn("BATCH_SUBMITTER_PRIVATE_KEY=", env_file) - self.assertIn("MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=", env_file) - self.assertIn("MORPH_ROLLUP_DEPLOY_BLOCK=", env_file) - - env_values = dict( - line.split("=", 1) - for line in env_file.splitlines() - if line and not line.startswith("#") - ) - self.assertNotEqual( - env_values["LEGACY_GENESIS_L1_STAKING_PROXY"].lower(), - env_values["MORPH_SUBMITTER"].lower(), - ) - - self.assertIn("TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER:?required}", compose) - self.assertIn( - "GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK=${MORPH_ROLLUP_DEPLOY_BLOCK:?required}", - compose, - ) - self.assertNotIn("l2StakingPks", devnet_source) - self.assertIn("--batch-submitter-private-key", devnet_source) - self.assertIn("env_data.pop('Proxy__L1Staking', None)", devnet_source) - self.assertIn("env_data.pop('MORPH_L1STAKING', None)", devnet_source) - self.assertIn( - "live Proxy__Submitter must differ from immutable legacy L1 staking fixture", - devnet_source, - ) - if __name__ == "__main__": unittest.main() diff --git a/ops/docker/.env b/ops/docker/.env index 3d1c7c4c1..670440268 100644 --- a/ops/docker/.env +++ b/ops/docker/.env @@ -7,13 +7,9 @@ L1_BEACON_CHAIN_RPC=http://layer1-cl:4000 L1_CROSS_DOMAIN_MESSENGER=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 MORPH_PORTAL=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 MORPH_ROLLUP=0xa513e6e4b8f2a923d98304ec87f64353c4d5c853 -MORPH_ROLLUP_DEPLOY_BLOCK=1 -LEGACY_GENESIS_L1_STAKING_PROXY=0x000000000000000000000000000000000000dEaD BUILD_GETH=l2-geth RUST_LOG=info +Proxy__L1Staking=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 BATCH_UPGRADE_TIME=0 +MORPH_L1STAKING=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 L1_SEQUENCER_CONTRACT=0x0165878a594ca255338adfa4d48449f69242eb8f -MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=5280d0eee2a64d3ad29480d15ffd1b048ce5908f180b5ccd65cc3dcf00941abb -BATCH_SUBMITTER_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d -Proxy__Submitter=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 -MORPH_SUBMITTER=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 diff --git a/ops/docker/Dockerfile.oracle b/ops/docker/Dockerfile.oracle index c0e2a5a3d..b25c1fdac 100644 --- a/ops/docker/Dockerfile.oracle +++ b/ops/docker/Dockerfile.oracle @@ -1,7 +1,7 @@ -FROM rust:1.91.0-slim as builder +FROM rust:1.88-slim as builder RUN apt-get -qq update && apt-get -qq install -y --no-install-recommends \ - build-essential pkg-config libssl-dev && rm -rf /var/lib/apt/lists/* + pkg-config libssl-dev && rm -rf /var/lib/apt/lists/* COPY ./gas-oracle /gas-oracle @@ -9,8 +9,6 @@ WORKDIR /gas-oracle RUN cd app && cargo build --release FROM ubuntu:22.04 as app -RUN apt-get -qq update && apt-get -qq install -y --no-install-recommends \ - ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /gas-oracle/app/target/release/app / -CMD ["./app"] +CMD ["./app"] \ No newline at end of file diff --git a/ops/docker/docker-compose-cluster.yml b/ops/docker/docker-compose-cluster.yml index 900f10ee7..f5c75e6fb 100644 --- a/ops/docker/docker-compose-cluster.yml +++ b/ops/docker/docker-compose-cluster.yml @@ -103,7 +103,6 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_BOOTSTRAP=true - MORPH_NODE_HA_SERVER_ID=ha-node-0 @@ -144,7 +143,6 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_JOIN=ha-node-0:9401 - MORPH_NODE_HA_SERVER_ID=ha-node-1 @@ -185,7 +183,6 @@ services: - MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-1} - MORPH_NODE_UPGRADE_BATCH_TIME=${BATCH_UPGRADE_TIME} - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} - MORPH_NODE_HA_ENABLED=true - MORPH_NODE_HA_JOIN=ha-node-0:9401 - MORPH_NODE_HA_SERVER_ID=ha-node-2 diff --git a/ops/docker/docker-compose-devnet.yml b/ops/docker/docker-compose-devnet.yml index 6809d24a8..451cd5e16 100644 --- a/ops/docker/docker-compose-devnet.yml +++ b/ops/docker/docker-compose-devnet.yml @@ -185,7 +185,6 @@ services: - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - MORPH_NODE_SEQUENCER_PRIVATE_KEY=${ACTIVE_SEQUENCER_PRIVATE_KEY} - MORPH_NODE_SEQUENCER_UPGRADE_TIME=${SEQUENCER_UPGRADE_TIME:-0} - - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} volumes: - ".devnet/node0:${NODE_DATA_DIR}" - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" @@ -222,7 +221,6 @@ services: - MORPH_NODE_L1_SEQUENCER_CONTRACT=${L1_SEQUENCER_CONTRACT} - MORPH_NODE_SEQUENCER_UPGRADE_TIME=${SEQUENCER_UPGRADE_TIME:-0} - MORPH_NODE_DERIVATION_VERIFY_MODE=layer1 - - MORPH_NODE_STATIC_VALIDATOR_TM_KEYS=${MORPH_NODE_STATIC_VALIDATOR_TM_KEYS:?required} volumes: - ".devnet/node1:${NODE_DATA_DIR}" - "${PWD}/jwt-secret.txt:${JWT_SECRET_PATH}" @@ -249,16 +247,16 @@ services: environment: - TX_SUBMITTER_BUILD_ENV=dev - TX_SUBMITTER_L1_ETH_RPC=${L1_ETH_RPC} - - TX_SUBMITTER_L1_PRIVATE_KEY=${BATCH_SUBMITTER_PRIVATE_KEY:?required} + - TX_SUBMITTER_L1_PRIVATE_KEY=0xd99870855d97327d20c666abc78588f1449b1fac76ed0c86c1afb9ce2db85f32 - TX_SUBMITTER_L2_ETH_RPCS=http://morph-el-0:8545,http://morph-el-1:8545 - TX_SUBMITTER_TX_TIMEOUT=60s - TX_SUBMITTER_ROLLUP_ADDRESS=${MORPH_ROLLUP:-0x6900000000000000000000000000000000000010} - - TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER:?required} - TX_SUBMITTER_FINALIZE=true + - TX_SUBMITTER_PRIORITY_ROLLUP=true - TX_SUBMITTER_SEAL_BATCH=true - - TX_SUBMITTER_BATCH_BLOCK_INTERVAL=200 - - TX_SUBMITTER_BATCH_TIMEOUT=600 - TX_SUBMITTER_TX_FEE_LIMIT=500000000000000000 + - TX_SUBMITTER_L1_STAKING_ADDRESS=${MORPH_L1STAKING:-0x5fc8d32690cc91d4c39d9d3abcbd16989f875707} + - TX_SUBMITTER_L1_STAKING_DEPLOYED_BLOCKNUM=0 - TX_SUBMITTER_BATCH_V2_UPGRADE_TIME=1777533291 gas-price-oracle: @@ -278,7 +276,6 @@ services: environment: - GAS_ORACLE_L1_RPC=${L1_ETH_RPC} - GAS_ORACLE_L1_BEACON_RPC=${L1_BEACON_CHAIN_RPC} - - GAS_ORACLE_L1_ROLLUP_DEPLOY_BLOCK=${MORPH_ROLLUP_DEPLOY_BLOCK:?required} - GAS_ORACLE_L2_RPC=http://morph-el-0:8545 - GAS_THRESHOLD=5 - INTERVAL=28000 diff --git a/prover/Makefile b/prover/Makefile index 6328e1661..d55f0bb46 100644 --- a/prover/Makefile +++ b/prover/Makefile @@ -1,5 +1,3 @@ -RUST_TOOLCHAIN ?= 1.91.0 - start-server: docker compose -f docker-compose-app.yml up -d @@ -8,7 +6,7 @@ stop-server: build-shadow-prove: - cd bin/shadow-prove && cargo +$(RUST_TOOLCHAIN) build --release + cd bin/shadow-prove && cargo build --release build-challenge: - cd bin/challenge && cargo +$(RUST_TOOLCHAIN) build --release + cd bin/challenge && cargo build --release diff --git a/prover/bin/challenge/.env.dev b/prover/bin/challenge/.env.dev index e0b5e4a3e..b5224a629 100644 --- a/prover/bin/challenge/.env.dev +++ b/prover/bin/challenge/.env.dev @@ -3,20 +3,12 @@ HANDLER_L1_RPC = "http://localhost:8545" HANDLER_L2_RPC = "http://localhost:8545" HANDLER_PROVER_RPC ="http://localhost:3030" HANDLER_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" -# Development fixture only. Production must use the archived Rollup proxy -# deployment block from the deployment manifest. -HANDLER_L1_ROLLUP_DEPLOY_BLOCK = 1 CHALLENGE_HANDLER_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" -# Comma-separated, explicitly approved local failover keys. The primary key is -# always evaluated first and no backup is used unless its address is active at -# the same finalized L1 snapshot. -CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS = "" SHADOW_PROVING = true # challenger CHALLENGER_L1_RPC = "http://localhost:8545" CHALLENGER_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" -CHALLENGER_L1_ROLLUP_DEPLOY_BLOCK = 1 CHALLENGER_PRIVATEKEY = "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" diff --git a/prover/bin/challenge/src/abi/Rollup.json b/prover/bin/challenge/src/abi/Rollup.json index e9da0e250..28f7a5c6d 100644 --- a/prover/bin/challenge/src/abi/Rollup.json +++ b/prover/bin/challenge/src/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -325,25 +306,6 @@ "name": "UpdateProofWindow", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +364,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +441,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,121 +637,33 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ + }, { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "signature", "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" } ], - "name": "commitState", + "name": "commitBatch", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -924,7 +779,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -971,32 +826,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +864,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1100,25 +942,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "pendingBatchCount", - "outputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proofRewardPercent", @@ -1145,24 +968,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proveRemaining", @@ -1245,19 +1050,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1271,19 +1063,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1336,19 +1115,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/prover/bin/challenge/src/abi/Submitter.json b/prover/bin/challenge/src/abi/Submitter.json deleted file mode 100644 index 85eeb4d97..000000000 --- a/prover/bin/challenge/src/abi/Submitter.json +++ /dev/null @@ -1,660 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldValue", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newValue", - "type": "uint256" - } - ], - "name": "ChallengeDepositUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "CreditClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldValue", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newValue", - "type": "uint256" - } - ], - "name": "MinimumStakeUpdated", - "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": false, - "internalType": "uint256", - "name": "oldValue", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newValue", - "type": "uint256" - } - ], - "name": "RewardPercentageUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "SlashRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "reward", - "type": "uint256" - } - ], - "name": "Slashed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "total", - "type": "uint256" - } - ], - "name": "Staked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "SubmitterAdded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "SubmitterRemoved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "totalCredit", - "type": "uint256" - } - ], - "name": "WithdrawalCredited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "WithdrawalPaid", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "submitter", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "WithdrawalRequested", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "addSubmitter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "challengeDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimCredit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimSlashRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimWithdrawal", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "claimable", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "exiting", - "outputs": [ - { - "internalType": "bool", - "name": "isExiting", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner_", - "type": "address" - }, - { - "internalType": "address", - "name": "rollupContract_", - "type": "address" - }, - { - "internalType": "uint256", - "name": "minimumStake_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "challengeDeposit_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "rewardPercentage_", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "isActive", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "minimumStake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "registered", - "outputs": [ - { - "internalType": "bool", - "name": "isRegistered", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "removeSubmitter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "rewardPercentage", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "setMinimumStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "slash", - "outputs": [ - { - "internalType": "uint256", - "name": "reward", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "slashRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "updateChallengeDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index f6a612f04..5e88bf9fa 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -7,18 +7,3 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } - -pub mod pre_submitter_rollup_abi { - use ethers::prelude::abigen; - abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); -} - -pub mod legacy_l1_staking_abi { - use ethers::prelude::abigen; - abigen!(LegacyL1Staking, "src/abi/pre_submitter/LegacyL1Staking.json"); -} - -pub mod submitter_abi { - use ethers::prelude::abigen; - abigen!(Submitter, "src/abi/Submitter.json"); -} diff --git a/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json b/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json deleted file mode 100644 index 9d0abd2e7..000000000 --- a/prover/bin/challenge/src/abi/pre_submitter/LegacyL1Staking.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "inputs": [], - "name": "challengeDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "isActiveStaker", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index 29aa69c96..5c100b9f4 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -1,6 +1,4 @@ use challenge_handler::abi::rollup_abi::Rollup; -use challenge_handler::rollup_compat::{challenge_deposit_at, CanonicalLogIndex}; -use challenge_handler::util::read_parse_env; use dotenv::dotenv; use env_logger::Env; use ethers::prelude::*; @@ -41,7 +39,6 @@ pub async fn challenge() -> Result<(), Box> { let l1_rpc = var("CHALLENGER_L1_RPC").expect("Cannot detect L1_RPC env var"); let l1_rollup_address = var("CHALLENGER_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let private_key = var("CHALLENGER_PRIVATEKEY").expect("Cannot detect CHALLENGER_PRIVATEKEY env var"); - let rollup_deployed_block: u64 = read_parse_env("CHALLENGER_L1_ROLLUP_DEPLOY_BLOCK"); let l1_provider: Provider = Provider::::try_from(l1_rpc)?; let l1_signer = Arc::new(SignerMiddleware::new( l1_provider.clone(), @@ -69,35 +66,21 @@ pub async fn challenge() -> Result<(), Box> { let proof_window = l1_rollup.proof_window().await?; log::info!("finalization_period: {:#?} proof_window: {:#?}", finalization_period, proof_window); - let mut canonical_log_index = CanonicalLogIndex::new(rollup_deployed_block)?; + let min_deposit: U256 = U256::from(4 * 10u128.pow(18)); + log::info!("min_deposit: {:#?}", min_deposit); + loop { - tokio::time::sleep(Duration::from_secs(12)).await; - if let Err(error) = auto_challenge(&l1_provider, &l1_rollup, &mut canonical_log_index).await { - log::error!("ALERT: auto-challenge iteration failed closed: {error:#}"); - } + std::thread::sleep(Duration::from_secs(12)); + let _ = auto_challenge(&l1_provider, &l1_rollup, min_deposit).await; } } -async fn auto_challenge( - l1_provider: &Provider, - l1_rollup: &RollupType, - canonical_log_index: &mut CanonicalLogIndex, -) -> Result<(), Box> { +async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, min_deposit: U256) -> Result<(), Box> { // Search for the latest batch. - let (latest, snapshot_hash) = match l1_provider.get_block(BlockNumber::Finalized).await { - Ok(Some(block)) => match (block.number, block.hash) { - (Some(number), Some(hash)) => (number, hash), - _ => { - log::error!("finalized L1 block has no stable identity"); - return Ok(()); - } - }, - Ok(None) => { - log::error!("finalized L1 block is unavailable"); - return Ok(()); - } + let latest = match l1_provider.get_block_number().await { + Ok(bn) => bn, Err(e) => { - log::error!("L1 provider.get finalized block error: {:#?}", e); + log::error!("L1 provider.get_block_number error: {:#?}", e); return Ok(()); } }; @@ -118,30 +101,44 @@ async fn auto_challenge( } log::info!("latest blocknum = {:#?}", latest); - let block_id = BlockId::Number(BlockNumber::Number(latest)); - let min_deposit = challenge_deposit_at(l1_rollup, block_id).await?; - let batch_index = l1_rollup.last_committed_batch_index().block(block_id).call().await?.as_u64(); - canonical_log_index - .refresh(l1_provider, l1_rollup.address(), latest, snapshot_hash) - .await?; - if canonical_log_index - .resolve(l1_rollup, batch_index, latest, snapshot_hash) - .await? - .is_none() - { - log::warn!("latest batch {batch_index} has no canonical Commit at fixed snapshot"); + let start = if latest > U64::from(600) { + latest - U64::from(600) + } else { + U64::from(1) + }; + + let filter = l1_rollup.commit_batch_filter().filter.from_block(start).address(l1_rollup.address()); + let mut logs: Vec = match l1_provider.get_logs(&filter).await { + Ok(logs) => logs, + Err(e) => { + log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); + return Ok(()); + } + }; + + if logs.is_empty() { + log::error!("There have been no commit_batch logs for the last 600 blocks."); return Ok(()); } + + logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); + let batch_index = match logs.get(logs.len() - 2) { + Some(log) => log.topics[1].to_low_u64_be(), + None => { + log::error!("find commit_batch log error"); + return Ok(()); + } + }; log::info!("latest batch index = {:#?}", batch_index); // Challenge state. - let is_batch_finalized = l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await?; + let is_batch_finalized = l1_rollup.is_batch_finalized(U256::from(batch_index)).await?; if is_batch_finalized { log::info!("is_batch_finalized = true, No need for challenge, batch index = {:#?}", batch_index); return Ok(()); } - let challenges = match l1_rollup.challenges(U256::from(batch_index)).block(block_id).call().await { + let challenges = match l1_rollup.challenges(U256::from(batch_index)).await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.challenges error, batch index = {:#?}, {:#?}", batch_index, e); @@ -154,11 +151,7 @@ async fn auto_challenge( return Ok(()); } - let batch_hash = l1_rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?; - if !snapshot_unchanged(l1_provider, latest, snapshot_hash).await { - log::error!("finalized L1 snapshot changed while preparing auto-challenge"); - return Ok(()); - } + let batch_hash = l1_rollup.committed_batches(U256::from(batch_index)).await?; // l1_rollup.connect() let tx: FunctionCall<_, _, _> = l1_rollup.challenge_state(batch_index, batch_hash).value(min_deposit); @@ -217,13 +210,7 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr } else { U64::from(1) }; - let block_id = BlockId::Number(BlockNumber::Number(latest)); - let filter = l1_rollup - .challenge_state_filter() - .filter - .from_block(start) - .to_block(latest) - .address(l1_rollup.address()); + let filter = l1_rollup.challenge_state_filter().filter.from_block(start).address(l1_rollup.address()); let mut logs: Vec = match l1_provider.get_logs(&filter).await { Ok(logs) => logs, Err(e) => { @@ -240,22 +227,16 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr for log in logs { let batch_index: u64 = log.topics[1].to_low_u64_be(); - let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).block(block_id).call().await { + let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.batch_in_challenge error, batch index = {:#?}, {:#?}", batch_index, e); return None; } }; - let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await { - Ok(value) => value, - Err(err) => { - log::error!("query l1_rollup.is_batch_finalized failed: {err:#}"); - return None; - } - }; + let _is_batch_finalized: bool = l1_rollup.is_batch_finalized(U256::from(batch_index)).await.unwrap(); - if batch_in_challenge && !is_batch_finalized { + if batch_in_challenge { log::info!("prev challenge not finalized, batch index = {:#?}", batch_index); return Some(true); } @@ -265,13 +246,6 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr Some(false) } -async fn snapshot_unchanged(provider: &Provider, number: U64, expected_hash: H256) -> bool { - matches!( - provider.get_block(number).await, - Ok(Some(block)) if block.hash == Some(expected_hash) - ) -} - // Check layer2 state. async fn verify_state_transition() { // Do nothing diff --git a/prover/bin/challenge/src/external_sign.rs b/prover/bin/challenge/src/external_sign.rs index 627de3b08..fb4a28fa2 100644 --- a/prover/bin/challenge/src/external_sign.rs +++ b/prover/bin/challenge/src/external_sign.rs @@ -97,6 +97,7 @@ impl ExternalSign { return Err("ext_sign response sign data invalid".into()); } + let sig = hex::decode(&response.result.sign_datas[0].sign[2..])?; let signed_tx: Bytes = tx.rlp_signed(&Signature::try_from(sig.as_slice())?); Ok(signed_tx) @@ -140,7 +141,7 @@ impl ExternalSign { log::debug!("===payload: {:?}", serde_json::to_string(payload).unwrap()); let response: reqwest::Response = self.client.post(url).json(&payload).send().await?; log::info!("===do_request response: {:?}", response); - + let status = response.status(); if !status.is_success() { let text = response.text().await?; diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 68e199dd9..36eac035f 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,15 +1,13 @@ -use crate::abi::rollup_abi::Rollup; +use crate::abi::rollup_abi::{CommitBatchCall, Rollup}; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; -use crate::proof_signer::{select_active_proof_signer, ApprovedProofSigner}; -use crate::rollup_compat::{decode_batch_data_input, decode_batch_data_store_block_number, CanonicalCommit, CanonicalLogIndex}; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; -use ethers::prelude::*; use ethers::providers::{Http, Provider}; use ethers::signers::Wallet; use ethers::types::Address; use ethers::types::Bytes; +use ethers::{abi::AbiDecode, prelude::*}; use eyre::anyhow; use serde::{Deserialize, Serialize}; use std::env::var; @@ -17,7 +15,6 @@ use std::error::Error; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; -use tokio::sync::Mutex; use tokio::time::sleep; use transaction::eip2718::TypedTransaction; @@ -53,8 +50,7 @@ pub struct ChallengeHandler { l1_rollup: RollupType, l1_provider: Provider, l2_rpc: String, - proof_signers: Vec, - canonical_log_index: Arc>, + ext_signer: Option, } impl ChallengeHandler { @@ -64,10 +60,6 @@ impl ChallengeHandler { let l2_rpc = var("HANDLER_L2_RPC").expect("Cannot detect L2_RPC env var"); let l1_rollup_address = var("HANDLER_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let _ = var("HANDLER_PROVER_RPC").expect("Cannot detect PROVER_RPC env var"); - let rollup_deployed_block: u64 = read_parse_env("HANDLER_L1_ROLLUP_DEPLOY_BLOCK"); - let canonical_log_index = Arc::new(Mutex::new( - CanonicalLogIndex::new(rollup_deployed_block).expect("HANDLER_L1_ROLLUP_DEPLOY_BLOCK must be non-zero"), - )); let private_key = read_env_var( "CHALLENGE_HANDLER_PRIVATE_KEY", @@ -75,14 +67,17 @@ impl ChallengeHandler { ); let l1_provider: Provider = Provider::::try_from(l1_rpc).unwrap(); - let chain_id = l1_provider.get_chainid().await.unwrap().as_u64(); - let local_wallet = Wallet::from_str(private_key.as_str()).unwrap().with_chain_id(chain_id); - let l1_signer = Arc::new(SignerMiddleware::new(l1_provider.clone(), local_wallet.clone())); + let l1_signer = Arc::new(SignerMiddleware::new( + l1_provider.clone(), + Wallet::from_str(private_key.as_str()) + .unwrap() + .with_chain_id(l1_provider.get_chainid().await.unwrap().as_u64()), + )); let l1_rollup: RollupType = Rollup::new(Address::from_str(l1_rollup_address.as_str()).unwrap(), l1_signer); let use_ext_sign: bool = read_env_var("HANDLER_EXTERNAL_SIGN", false); - let primary_signer = if use_ext_sign { + let ext_signer = if use_ext_sign { log::info!("Challenge handler will use external signer"); let handler_appid: String = read_parse_env("HANDLER_EXTERNAL_SIGN_APPID"); let privkey_pem: String = read_parse_env("HANDLER_EXTERNAL_SIGN_RSA_PRIV"); @@ -92,32 +87,17 @@ impl ChallengeHandler { let signer: ExternalSign = ExternalSign::new(&handler_appid, &privkey_pem, &sign_address, &sign_chain, &sign_url) .map_err(|e| anyhow!(format!("Prepare ExternalSign err: {:?}", e))) .unwrap(); - let address = Address::from_str(&signer.address).expect("HANDLER_EXTERNAL_SIGN_ADDRESS must be a valid address"); - ApprovedProofSigner::external(address, signer) + Some(signer) } else { log::info!("Challenge handler will use local signer"); - ApprovedProofSigner::local(local_wallet) + None }; - let mut proof_signers = vec![primary_signer]; - let backup_private_keys: String = read_env_var("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS", String::new()); - for backup_private_key in backup_private_keys.split(',').map(str::trim).filter(|key| !key.is_empty()) { - let wallet = Wallet::from_str(backup_private_key) - .expect("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS contains an invalid private key") - .with_chain_id(chain_id); - if proof_signers.iter().any(|approved| approved.address() == wallet.address()) { - panic!("CHALLENGE_HANDLER_BACKUP_PRIVATE_KEYS contains a duplicate approved signer"); - } - proof_signers.push(ApprovedProofSigner::local(wallet)); - } - log::info!("Configured {} ordered approved proof signer(s)", proof_signers.len()); - Self { l1_rollup, l1_provider, l2_rpc, - proof_signers, - canonical_log_index, + ext_signer, } } @@ -129,42 +109,21 @@ impl ChallengeHandler { loop { sleep(Duration::from_secs(12)).await; - // A challenge win/slash does not terminate the batch. Keep the - // service in an explicit pending state until the owner executes - // the canonical RevertBatch and clears revertReqIndex. - match l1_rollup.revert_req_index().await { - Ok(index) if !index.is_zero() => { - log::warn!("challenge result is awaiting owner RevertBatch, revert_req_index={}", index); - continue; - } - Ok(_) => {} - Err(err) => { - log::error!("query revertReqIndex failed: {err:#}"); - continue; - } - } - // Step1. fetch latest blocknum. - let (latest, snapshot_hash) = match l1_provider.get_block(BlockNumber::Finalized).await { - Ok(Some(block)) => match (block.number, block.hash) { - (Some(number), Some(hash)) => (number, hash), - _ => { - log::error!("finalized L1 block has no stable identity"); - continue; - } - }, - Ok(None) => { - log::error!("finalized L1 block is unavailable"); - continue; - } + let latest = match l1_provider.get_block_number().await { + Ok(bn) => bn, Err(e) => { - log::error!("L1 provider.get finalized block error: {:#?}", e); + log::error!("L1 provider.get_block_number error: {:#?}", e); continue; } }; log::info!("Current L1 block number: {:#?}", latest); - let wallet = self.proof_signers[0].address(); + let wallet = if let Some(signer) = &self.ext_signer { + Address::from_str(&signer.address).unwrap_or_default() + } else { + self.l1_rollup.client().address() + }; // Record wallet balance. let balance = match l1_provider.get_balance(wallet, None).await { Ok(b) => b, @@ -187,13 +146,12 @@ impl ChallengeHandler { METRICS.detected_batch_index.set(batch_index as i64); // Step3. query challenged batch info. - let (challenged_commit, batch_hash) = - match query_batch_tx(latest, snapshot_hash, l1_rollup, batch_index, &self.canonical_log_index, l1_provider).await { - Some(value) => value, - None => continue, - }; + let (challenged_rollup_hash, batch_hash) = match query_batch_tx(latest, l1_rollup, batch_index, l1_provider).await { + Some(value) => value, + None => continue, + }; - let mut batch_info = match batch_inspect(l1_rollup, l1_provider, batch_index, &challenged_commit, latest).await { + let mut batch_info = match batch_inspect(l1_rollup, l1_provider, batch_index, challenged_rollup_hash).await { Some(mut b) => { b.batch_index = batch_index; b.parent_batch_hash = batch_hash.as_bytes().try_into().unwrap_or_default(); @@ -201,10 +159,6 @@ impl ChallengeHandler { } None => continue, }; - if !snapshot_unchanged(l1_provider, latest, snapshot_hash).await { - log::error!("finalized L1 snapshot changed while building challenge proof input"); - continue; - } let blocks_len = batch_info.end_block - batch_info.start_block + 1; log::info!( @@ -289,37 +243,12 @@ impl ChallengeHandler { async fn prove_state(&self, batch_index: u64, batch_header: Bytes, batch_proof: ProveResult, l1_rollup: &RollupType) -> bool { for _ in 0..MAX_RETRY_TIMES { sleep(Duration::from_secs(12)).await; - METRICS.proof_signer_available.set(0); - let selected = match select_active_proof_signer(l1_rollup, &self.proof_signers).await { - Ok(Some(selected)) => selected, - Ok(None) => { - log::error!( - "ALERT: refusing proveState because all {} approved proof signers are inactive; no transaction was sent", - self.proof_signers.len() - ); - return false; - } - Err(err) => { - log::error!("ALERT: refusing proveState because active signer selection failed: {err:#}; no transaction was sent"); - return false; - } - }; - METRICS.proof_signer_available.set(1); - if selected.approved_index > 0 { - log::warn!( - "ALERT: primary proof signer is inactive; switching to approved backup #{} {:?} at finalized snapshot {} ({:?})", - selected.approved_index, - selected.signer.address(), - selected.snapshot.number, - selected.snapshot.hash - ); - } log::info!("starting prove state onchain, batch index = {:#?}", batch_index); let proof = Bytes::from(batch_proof.proof_data.clone()); let client: Arc, LocalWallet>> = self.l1_rollup.client(); let calldata = l1_rollup.prove_state(batch_header.clone(), proof).calldata(); - let result = send_transaction(self.l1_rollup.address(), calldata, &client, &selected.signer, &self.l1_provider).await; + let result = send_transaction(self.l1_rollup.address(), calldata, &client, &self.ext_signer, &self.l1_provider).await; if let Ok(tx_hash) = result { METRICS.verify_result.set(1); log::info!("prove_state success, batch_index: {:?}, tx_hash: {:#?}", batch_index, tx_hash); @@ -363,42 +292,65 @@ async fn query_proof(batch_index: u64) -> Option { Some(prove_result) } -async fn query_batch_tx( - latest: U64, - snapshot_hash: H256, - l1_rollup: &RollupType, - batch_index: u64, - canonical_log_index: &Arc>, - l1_provider: &Provider, -) -> Option<(CanonicalCommit, H256)> { - let mut canonical_log_index = canonical_log_index.lock().await; - if let Err(err) = canonical_log_index.refresh(l1_provider, l1_rollup.address(), latest, snapshot_hash).await { - log::error!("canonical Commit index refresh failed: {err:#}"); - return None; - } - let commit = match canonical_log_index.resolve(l1_rollup, batch_index, latest, snapshot_hash).await { - Ok(Some(commit)) => commit, - Ok(None) => { - log::warn!("batch {batch_index} has no canonical Commit at snapshot {latest}"); - return None; - } - Err(err) => { - log::error!("canonical Commit resolution failed: {err:#}"); - return None; - } +async fn query_batch_tx(latest: U64, l1_rollup: &RollupType, batch_index: u64, l1_provider: &Provider) -> Option<(H256, H256)> { + let start = if latest > U64::from(7200 * 3) { + // Depends on challenge period + latest - U64::from(7200 * 3) + } else { + U64::from(1) }; - drop(canonical_log_index); - - let block_id = BlockId::Number(BlockNumber::Number(latest)); - let parent_index = batch_index.checked_sub(1)?; - let parent_hash: [u8; 32] = match l1_rollup.committed_batches(U256::from(parent_index)).block(block_id).call().await { - Ok(hash) => hash, - Err(err) => { - log::error!("query canonical parent batch hash failed: {err:#}"); + + let challenged_hash = query_tx_hash(l1_rollup, start, batch_index, l1_provider).await.or_else(|| { + log::warn!("challenged_hash is none"); + None + })?; + + let batch_hash: [u8; 32] = l1_rollup.committed_batches(U256::from(batch_index - 1)).await.unwrap_or_default(); + Some((challenged_hash, H256::from_slice(&batch_hash))) +} + +async fn query_tx_hash(l1_rollup: &RollupType, start: U64, batch_index: u64, l1_provider: &Provider) -> Option { + let filter = l1_rollup + .commit_batch_filter() + .filter + .from_block(start) + .topic1(U256::from(batch_index)) + .address(l1_rollup.address()); + let logs: Vec = match l1_provider.get_logs(&filter).await { + Ok(logs) => logs, + Err(e) => { + log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); return None; } }; - Some((commit, H256::from_slice(&parent_hash))) + if logs.is_empty() { + log::error!("no commit_batch log of {:?}, commit_batch logs is empty", batch_index); + return None; + } + for log in logs { + if log.topics[1].to_low_u64_be() != batch_index { + continue; + } + let tx_hash = log.transaction_hash.unwrap(); + let receipt = l1_provider.get_transaction_receipt(tx_hash).await.unwrap(); + match receipt { + Some(tr) => { + match tr.status.unwrap_or_default().as_u64() { + 1 => return Some(tx_hash), + _ => { + log::warn!("commit_batch receipt is fail: {:#?}", tr); + continue; + } + }; + } + None => { + log::warn!("no commit_batch receipt, batch index = {:?}, tx_hash = {:?}", batch_index, tx_hash); + } + } + } + log::error!("unable to find valid commit_batch log, batch index = {:?}", batch_index); + + None } async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provider: &Provider) -> Option { @@ -408,13 +360,7 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide } else { U64::from(1) }; - let block_id = BlockId::Number(BlockNumber::Number(latest)); - let filter = l1_rollup - .challenge_state_filter() - .filter - .from_block(start) - .to_block(latest) - .address(l1_rollup.address()); + let filter = l1_rollup.challenge_state_filter().filter.from_block(start).address(l1_rollup.address()); let mut logs: Vec = match l1_provider.get_logs(&filter).await { Ok(logs) => logs, Err(e) => { @@ -435,14 +381,14 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide for log in logs { let batch_index: u64 = log.topics[1].to_low_u64_be(); - let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).block(block_id).call().await { + let batch_in_challenge: bool = match l1_rollup.batch_in_challenge(U256::from(batch_index)).await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.batch_in_challenge error, batch index = {:#?}, {:#?}", batch_index, e); return None; } }; - let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).block(block_id).call().await { + let is_batch_finalized: bool = match l1_rollup.is_batch_finalized(U256::from(batch_index)).await { Ok(x) => x, Err(e) => { log::info!("query l1_rollup.is_batch_finalized error, batch index = {:#?}, {:#?}", batch_index, e); @@ -475,32 +421,16 @@ struct BatchInfo { parent_batch_hash: [u8; 32], } -async fn batch_inspect( - l1_rollup: &RollupType, - l1_provider: &Provider, - batch_index: u64, - commit: &CanonicalCommit, - snapshot: U64, -) -> Option { - let block_id = BlockId::Number(BlockNumber::Number(snapshot)); - let parent_index = batch_index.checked_sub(1)?; - let calldata = l1_rollup.batch_data_store(U256::from(parent_index)).calldata()?; - let request: TypedTransaction = TransactionRequest::new().to(l1_rollup.address()).data(calldata).into(); - let prev_batch_last_bn: U256 = match l1_provider.call(&request, Some(block_id)).await { - Ok(data) => match decode_batch_data_store_block_number(data.as_ref()) { - Ok(block_number) => block_number, - Err(error) => { - log::error!("decode compatible batchDataStore output failed: {error:#}"); - return None; - } - }, +async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, batch_index: u64, hash: TxHash) -> Option { + let prev_batch_last_bn: U256 = match l1_rollup.batch_data_store(U256::from(batch_index - 1)).await { + Ok(s) => s.2, Err(e) => { - log::error!("l1_rollup compatible batchDataStore call failed: {:#?}", e); + log::error!("l1_rollup.batch_data_store err: {:#?}", e); return None; } }; //Step1. Get transaction - let result = l1_provider.get_transaction(commit.transaction_hash).await; + let result = l1_provider.get_transaction(hash).await; let tx = match result { Ok(Some(tx)) => tx, Ok(None) => { @@ -512,35 +442,26 @@ async fn batch_inspect( return None; } }; - if tx.to != Some(l1_rollup.address()) - || tx.block_number != Some(commit.identity.block_number.into()) - || tx.block_hash != Some(commit.block_hash) - || tx.transaction_index != Some(commit.identity.transaction_index.into()) - { - log::error!("canonical Commit transaction identity changed"); - return None; - } //Step2. Parse transaction data let data = tx.input; if data.is_empty() { - log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", commit.transaction_hash); + log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let param = match decode_batch_data_input(&data) { - Ok(param) => param, - Err(err) => { - log::error!("batch inspect: decode tx.input error, tx_hash = {:?}: {err:#}", commit.transaction_hash); - return None; - } + let param = if let Ok(_param) = CommitBatchCall::decode(&data) { + _param + } else { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); + return None; }; - let version = param.version; - let prev_state_root = param.prev_state_root; - let post_state_root = param.post_state_root; - let withdrawal_root = param.withdrawal_root; - let last_block_number = param.last_block_number; - let num_l1_messages = param.num_l1_messages; + let version: u8 = param.batch_data_input.version; + let prev_state_root: [u8; 32] = param.batch_data_input.prev_state_root; + let post_state_root: [u8; 32] = param.batch_data_input.post_state_root; + let withdrawal_root: [u8; 32] = param.batch_data_input.withdrawal_root; + let last_block_number: u64 = param.batch_data_input.last_block_number; + let num_l1_messages = param.batch_data_input.num_l1_messages; log::info!("======> batch inspect: decode tx.input, version = {:#?}", version); log::info!("======> batch inspect: decode tx.input, param = {:#?}", param); @@ -556,7 +477,7 @@ async fn batch_inspect( }; // prev_batch_header - let prev_batch_header = param.parent_batch_header; + let prev_batch_header: Bytes = param.batch_data_input.parent_batch_header; let prev_total_l1_message = prev_batch_header.get(17..25).unwrap_or_default(); let post_total_l1_message = u64::from_be_bytes(prev_total_l1_message.try_into().unwrap()) + batch_info.l1_message_popped; batch_info.total_l1_message_popped = post_total_l1_message; @@ -564,13 +485,6 @@ async fn batch_inspect( Some(batch_info) } -async fn snapshot_unchanged(provider: &Provider, number: U64, expected_hash: H256) -> bool { - matches!( - provider.get_block(number).await, - Ok(Some(block)) if block.hash == Some(expected_hash) - ) -} - impl BatchInfo { fn fill_ext(&mut self, batch_header_ex: Vec) -> &Self { log::debug!("batch_header_ex len: {:#?}", batch_header_ex.len()); @@ -607,20 +521,23 @@ async fn send_transaction( contract: Address, calldata: Option, local_signer: &Arc, LocalWallet>>, - proof_signer: &ApprovedProofSigner, + ext_signer: &Option, l2_provider: &Provider, ) -> Result> { let req = Eip1559TransactionRequest::new().data(calldata.unwrap_or_default()); let mut tx = TypedTransaction::Eip1559(req); tx.set_to(contract); - tx.set_from(proof_signer.address()); + if let Some(signer) = ext_signer { + tx.set_from(Address::from_str(&signer.address).unwrap_or_default()); + } else { + tx.set_from(local_signer.address()); + } local_signer.fill_transaction(&mut tx, None).await.map_err(|e| { let msg = contract_error(ContractError::, LocalWallet>>::from_middleware_error(e)); anyhow!("prove_state fill_transaction error: {:#?}", msg) })?; - let signed_tx = proof_signer - .sign_transaction(&tx) + let signed_tx = sign_tx(tx, local_signer, ext_signer) .await .map_err(|e| anyhow!("prove_state sign_tx error: {}", e))?; @@ -643,6 +560,19 @@ async fn send_transaction( } } +async fn sign_tx( + tx: TypedTransaction, + local_signer: &Arc, LocalWallet>>, + ext_signer: &Option, +) -> Result> { + if let Some(signer) = ext_signer { + Ok(signer.request_sign(&tx).await?) + } else { + let signature = local_signer.signer().sign_transaction(&tx).await?; + Ok(tx.rlp_signed(&signature)) + } +} + pub fn contract_error(e: ContractError) -> String { let error_msg = if let Some(contract_err) = e.as_revert() { format!("contract error: {:?}", contract_err) @@ -650,4 +580,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:?}", e) }; error_msg -} +} \ No newline at end of file diff --git a/prover/bin/challenge/src/lib.rs b/prover/bin/challenge/src/lib.rs index 025c2c899..92477d8b2 100644 --- a/prover/bin/challenge/src/lib.rs +++ b/prover/bin/challenge/src/lib.rs @@ -1,7 +1,6 @@ pub mod abi; -mod external_sign; pub mod handler; pub mod metrics; -pub mod proof_signer; -pub mod rollup_compat; pub mod util; +mod external_sign; + diff --git a/prover/bin/challenge/src/main.rs b/prover/bin/challenge/src/main.rs index 0d2919caa..f134ac403 100644 --- a/prover/bin/challenge/src/main.rs +++ b/prover/bin/challenge/src/main.rs @@ -54,8 +54,6 @@ fn register_metrics() { REGISTRY.register(Box::new(METRICS.verify_result.clone())).unwrap(); // wallet balance. REGISTRY.register(Box::new(METRICS.wallet_balance.clone())).unwrap(); - // approved active proof signer availability. - REGISTRY.register(Box::new(METRICS.proof_signer_available.clone())).unwrap(); } async fn handle_metrics() -> String { diff --git a/prover/bin/challenge/src/metrics.rs b/prover/bin/challenge/src/metrics.rs index 013918216..480d01f26 100644 --- a/prover/bin/challenge/src/metrics.rs +++ b/prover/bin/challenge/src/metrics.rs @@ -6,7 +6,6 @@ pub struct Metrics { pub blocks_len: IntGauge, pub verify_result: IntGauge, pub wallet_balance: Gauge, - pub proof_signer_available: IntGauge, } lazy_static! { @@ -16,7 +15,5 @@ lazy_static! { blocks_len: IntGauge::new("blocks_len", "blocks len").expect("blocks_len metric can be created"), verify_result: IntGauge::new("verify_result", "verify result").expect("verify metric can be created"), wallet_balance: Gauge::new("handler_wallet_balance", "handler wallet balance").expect("wallet metric can be created"), - proof_signer_available: IntGauge::new("proof_signer_available", "whether an approved proof signer is active") - .expect("proof signer metric can be created"), }; } diff --git a/prover/bin/challenge/src/proof_signer.rs b/prover/bin/challenge/src/proof_signer.rs deleted file mode 100644 index 9ead803a8..000000000 --- a/prover/bin/challenge/src/proof_signer.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::abi::rollup_abi::Rollup; -use crate::external_sign::ExternalSign; -use crate::rollup_compat::authority_is_active; -use ethers::prelude::{BlockId, BlockNumber, LocalWallet, Middleware, Signer}; -use ethers::types::{transaction::eip2718::TypedTransaction, Address, Bytes, H256, U64}; -use eyre::{eyre, Result}; -use std::future::Future; - -#[derive(Clone)] -pub enum ApprovedProofSigner { - Local(LocalWallet), - External { address: Address, signer: Box }, -} - -impl ApprovedProofSigner { - pub fn local(wallet: LocalWallet) -> Self { - Self::Local(wallet) - } - - pub fn external(address: Address, signer: ExternalSign) -> Self { - Self::External { - address, - signer: Box::new(signer), - } - } - - pub fn address(&self) -> Address { - match self { - Self::Local(wallet) => wallet.address(), - Self::External { address, .. } => *address, - } - } - - pub async fn sign_transaction(&self, tx: &TypedTransaction) -> Result { - match self { - Self::Local(wallet) => { - let signature = wallet.sign_transaction(tx).await?; - Ok(tx.rlp_signed(&signature)) - } - Self::External { signer, .. } => signer.request_sign(tx).await.map_err(|err| eyre!(err.to_string())), - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct FixedSnapshot { - pub number: U64, - pub hash: H256, -} - -#[derive(Clone)] -pub struct SelectedProofSigner { - pub signer: ApprovedProofSigner, - pub approved_index: usize, - pub snapshot: FixedSnapshot, -} - -async fn first_active_index(approved: &[Address], mut is_active: F) -> std::result::Result, E> -where - F: FnMut(Address) -> Fut, - Fut: Future>, -{ - for (index, address) in approved.iter().copied().enumerate() { - if is_active(address).await? { - return Ok(Some(index)); - } - } - Ok(None) -} - -async fn fixed_finalized_snapshot(client: &M) -> Result { - let block = client - .get_block(BlockNumber::Finalized) - .await - .map_err(|err| eyre!("query finalized L1 snapshot failed: {err}"))? - .ok_or_else(|| eyre!("finalized L1 block is unavailable"))?; - let number = block.number.ok_or_else(|| eyre!("finalized L1 block has no number"))?; - let hash = block.hash.ok_or_else(|| eyre!("finalized L1 block has no hash"))?; - Ok(FixedSnapshot { number, hash }) -} - -async fn ensure_snapshot_unchanged(client: &M, snapshot: FixedSnapshot) -> Result<()> { - let current = client - .get_block(snapshot.number) - .await - .map_err(|err| eyre!("recheck finalized L1 snapshot failed: {err}"))? - .ok_or_else(|| eyre!("finalized L1 snapshot disappeared during signer selection"))?; - if current.hash != Some(snapshot.hash) { - return Err(eyre!("finalized L1 snapshot changed during signer selection")); - } - Ok(()) -} - -/// Selects the first approved signer that is active at one immutable finalized -/// block hash. The caller must treat `None` and every error as a hard no-send. -pub async fn select_active_proof_signer( - rollup: &Rollup, - approved: &[ApprovedProofSigner], -) -> Result> { - if approved.is_empty() { - return Err(eyre!("no approved proof signers are configured")); - } - - let snapshot = fixed_finalized_snapshot(rollup.client().as_ref()).await?; - let block_id = BlockId::Hash(snapshot.hash); - let addresses = approved.iter().map(ApprovedProofSigner::address).collect::>(); - let approved_index = first_active_index(&addresses, |address| async move { - authority_is_active(rollup, address, block_id) - .await - .map_err(|err| eyre!("active check failed for approved proof signer {address:?}: {err}")) - }) - .await?; - ensure_snapshot_unchanged(rollup.client().as_ref(), snapshot).await?; - Ok(approved_index.map(|approved_index| SelectedProofSigner { - signer: approved[approved_index].clone(), - approved_index, - snapshot, - })) -} - -#[cfg(test)] -mod tests { - use super::first_active_index; - use ethers::types::Address; - use std::convert::Infallible; - use std::future::ready; - - #[tokio::test] - async fn primary_inactivation_selects_first_active_backup() { - let primary = Address::from_low_u64_be(1); - let backup = Address::from_low_u64_be(2); - let approved = [primary, backup]; - - let initial = first_active_index(&approved, |_| ready(Ok::<_, Infallible>(true))).await.unwrap(); - let after_primary_inactivation = first_active_index(&approved, |address| ready(Ok::<_, Infallible>(address == backup))) - .await - .unwrap(); - - assert_eq!(initial, Some(0)); - assert_eq!(after_primary_inactivation, Some(1)); - } - - #[tokio::test] - async fn all_inactive_signers_fail_closed_without_dispatch() { - let approved = [Address::from_low_u64_be(1), Address::from_low_u64_be(2)]; - let selected = first_active_index(&approved, |_| ready(Ok::<_, Infallible>(false))).await.unwrap(); - let mut sent_transactions = 0; - if selected.is_some() { - sent_transactions += 1; - } - - assert_eq!(selected, None); - assert_eq!(sent_transactions, 0); - } -} diff --git a/prover/bin/challenge/src/rollup_compat.rs b/prover/bin/challenge/src/rollup_compat.rs deleted file mode 100644 index 8ea74f73e..000000000 --- a/prover/bin/challenge/src/rollup_compat.rs +++ /dev/null @@ -1,546 +0,0 @@ -use ethers::{ - abi::AbiDecode, - providers::Middleware, - types::{transaction::eip2718::TypedTransaction, Address, BlockId, BlockNumber, Bytes, Filter, Log, TransactionRequest, TxHash, H256, U256, U64}, - utils::{id, keccak256}, -}; -use eyre::{eyre, Result}; -use std::collections::HashMap; - -use crate::abi::{ - legacy_l1_staking_abi::LegacyL1Staking, - pre_submitter_rollup_abi::{ - CommitBatchCall as PreSubmitterCommitBatchCall, CommitBatchWithProofCall as PreSubmitterCommitBatchWithProofCall, - CommitStateCall as PreSubmitterCommitStateCall, - }, - rollup_abi::{CommitBatchCall, CommitBatchWithProofCall, CommitStateCall, Rollup}, - submitter_abi::Submitter, -}; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum AuthorityKind { - LegacyL1Staking, - Submitter, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RollupAuthority { - pub address: Address, - pub kind: AuthorityKind, -} - -fn decode_address_word(data: &[u8]) -> Result
{ - if data.len() != 32 || data[..12].iter().any(|byte| *byte != 0) { - return Err(eyre!("authority getter returned malformed address data")); - } - let address = Address::from_slice(&data[12..]); - if address.is_zero() { - return Err(eyre!("authority getter returned zero address")); - } - Ok(address) -} - -pub async fn resolve_rollup_authority(rollup: &Rollup, snapshot: BlockId) -> Result { - match rollup.submitter_contract().block(snapshot).call().await { - Ok(address) if !address.is_zero() => Ok(RollupAuthority { - address, - kind: AuthorityKind::Submitter, - }), - Ok(_) => Err(eyre!("Rollup.submitterContract returned zero address")), - Err(current_error) => { - // Before initialize4 the proxy still runs the frozen Rollup ABI and - // rejects submitterContract(). Read the old slot through its - // historical getter at the exact same numbered snapshot. - let request: TypedTransaction = TransactionRequest::new() - .to(rollup.address()) - .data(Bytes::from(id("l1StakingContract()")[..4].to_vec())) - .into(); - let output = rollup.client().call(&request, Some(snapshot)).await.map_err(|legacy_error| { - eyre!("neither current nor pre-submit authority getter succeeded: current={current_error}; legacy={legacy_error}") - })?; - Ok(RollupAuthority { - address: decode_address_word(output.as_ref())?, - kind: AuthorityKind::LegacyL1Staking, - }) - } - } -} - -pub async fn authority_is_active(rollup: &Rollup, signer: Address, snapshot: BlockId) -> Result { - let authority = resolve_rollup_authority(rollup, snapshot).await?; - match authority.kind { - AuthorityKind::Submitter => Ok(Submitter::new(authority.address, rollup.client()) - .is_active(signer) - .block(snapshot) - .call() - .await?), - AuthorityKind::LegacyL1Staking => Ok(LegacyL1Staking::new(authority.address, rollup.client()) - .is_active_staker(signer) - .block(snapshot) - .call() - .await?), - } -} - -pub async fn challenge_deposit_at(rollup: &Rollup, snapshot: BlockId) -> Result { - let authority = resolve_rollup_authority(rollup, snapshot).await?; - match authority.kind { - AuthorityKind::Submitter => Ok(Submitter::new(authority.address, rollup.client()) - .challenge_deposit() - .block(snapshot) - .call() - .await?), - AuthorityKind::LegacyL1Staking => Ok(LegacyL1Staking::new(authority.address, rollup.client()) - .challenge_deposit() - .block(snapshot) - .call() - .await?), - } -} - -pub fn decode_batch_data_store_block_number(data: &[u8]) -> Result { - if data.len() != 128 { - return Err(eyre!("batchDataStore returned {}, expected exactly 128 bytes", data.len())); - } - Ok(U256::from_big_endian(&data[64..96])) -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum SubmissionKind { - CommitBatch, - CommitState, - CommitBatchWithProof, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BatchDataInput { - pub version: u8, - pub parent_batch_header: Bytes, - pub last_block_number: u64, - pub num_l1_messages: u16, - pub prev_state_root: [u8; 32], - pub post_state_root: [u8; 32], - pub withdrawal_root: [u8; 32], - pub kind: SubmissionKind, - pub pre_submitter: bool, -} - -macro_rules! decoded { - ($input:expr, $kind:expr, $pre:expr) => {{ - let input = $input; - BatchDataInput { - version: input.version, - parent_batch_header: input.parent_batch_header, - last_block_number: input.last_block_number, - num_l1_messages: input.num_l1_messages, - prev_state_root: input.prev_state_root, - post_state_root: input.post_state_root, - withdrawal_root: input.withdrawal_root, - kind: $kind, - pre_submitter: $pre, - } - }}; -} - -pub fn decode_batch_data_input(data: &[u8]) -> Result { - if data.len() < 4 { - return Err(eyre!("rollup calldata is shorter than a selector")); - } - - if let Ok(call) = CommitBatchCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, false)); - } - if let Ok(call) = CommitStateCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, false)); - } - if let Ok(call) = CommitBatchWithProofCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, false)); - } - - if let Ok(call) = PreSubmitterCommitBatchCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatch, true)); - } - if let Ok(call) = PreSubmitterCommitStateCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitState, true)); - } - if let Ok(call) = PreSubmitterCommitBatchWithProofCall::decode(data) { - return Ok(decoded!(call.batch_data_input, SubmissionKind::CommitBatchWithProof, true)); - } - - Err(eyre!("unsupported rollup submission selector")) -} - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct LogIdentity { - pub block_number: u64, - pub transaction_index: u64, - pub log_index: u64, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CanonicalCommit { - pub identity: LogIdentity, - pub transaction_hash: TxHash, - pub block_hash: H256, - pub batch_hash: H256, -} - -fn identity(log: &Log) -> Option { - Some(LogIdentity { - block_number: log.block_number?.as_u64(), - transaction_index: log.transaction_index?.as_u64(), - log_index: log.log_index?.as_u64(), - }) -} - -pub fn select_canonical_commit(commits: &[Log], reverts: &[Log], canonical_hash: H256) -> Option { - if canonical_hash.is_zero() { - return None; - } - let last_revert = reverts.iter().filter(|log| !log.removed.unwrap_or_default()).filter_map(identity).max(); - - commits - .iter() - .filter(|log| !log.removed.unwrap_or_default()) - .filter_map(|log| { - let identity = identity(log)?; - if last_revert.is_some_and(|revert| identity <= revert) { - return None; - } - if log.topics.len() < 3 || log.topics[2] != canonical_hash { - return None; - } - Some(CanonicalCommit { - identity, - transaction_hash: log.transaction_hash?, - block_hash: log.block_hash?, - batch_hash: log.topics[2], - }) - }) - .max_by_key(|commit| commit.identity) -} - -const QUERY_RANGE: u64 = 10_000; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -struct IndexedSnapshot { - number: u64, - hash: H256, -} - -/// Reusable finalized Commit/Revert index. The first poll replays from the -/// configured Rollup deployment block; subsequent polls validate the previous -/// block-hash anchor and query only the newly finalized suffix. -#[derive(Debug)] -pub struct CanonicalLogIndex { - rollup_deployed_block: u64, - indexed_snapshot: Option, - commits: HashMap>, - reverts: HashMap>, -} - -impl CanonicalLogIndex { - pub fn new(rollup_deployed_block: u64) -> Result { - if rollup_deployed_block == 0 { - return Err(eyre!("Rollup deployment block must be non-zero")); - } - Ok(Self { - rollup_deployed_block, - indexed_snapshot: None, - commits: HashMap::new(), - reverts: HashMap::new(), - }) - } - - fn clear(&mut self) { - self.indexed_snapshot = None; - self.commits.clear(); - self.reverts.clear(); - } - - fn query_start(&self, snapshot_number: u64) -> Result> { - if snapshot_number < self.rollup_deployed_block { - return Err(eyre!( - "Rollup deployment block {} is newer than snapshot {snapshot_number}", - self.rollup_deployed_block - )); - } - match self.indexed_snapshot { - None => Ok(Some(self.rollup_deployed_block)), - Some(indexed) if snapshot_number < indexed.number => Err(eyre!( - "finalized snapshot moved backwards: indexed={}, requested={snapshot_number}", - indexed.number - )), - Some(indexed) if snapshot_number == indexed.number => Ok(None), - Some(indexed) => Ok(Some( - indexed.number.checked_add(1).ok_or_else(|| eyre!("canonical log index block overflow"))?, - )), - } - } - - fn verify_cached_anchor(&mut self, observed_hash: H256) -> Result<()> { - let Some(indexed) = self.indexed_snapshot else { - return Ok(()); - }; - if indexed.hash != observed_hash { - self.clear(); - return Err(eyre!("canonical log index anchor changed at block {}; cache discarded", indexed.number)); - } - Ok(()) - } - - fn batch_index(log: &Log) -> Result { - if log.removed.unwrap_or_default() { - return Err(eyre!("removed log returned for finalized canonical range")); - } - identity(log).ok_or_else(|| eyre!("canonical Rollup log has incomplete identity"))?; - if log.transaction_hash.is_none() || log.block_hash.is_none() { - return Err(eyre!("canonical Rollup log has incomplete block/transaction identity")); - } - if log.topics.len() < 3 { - return Err(eyre!("canonical Rollup log is missing indexed topics")); - } - let batch_index = U256::from_big_endian(log.topics[1].as_bytes()); - if batch_index > U256::from(u64::MAX) { - return Err(eyre!("Rollup batch index exceeds u64")); - } - Ok(batch_index.as_u64()) - } - - fn append_logs(&mut self, snapshot_number: u64, snapshot_hash: H256, commits: Vec, reverts: Vec) -> Result<()> { - let mut indexed_commits = Vec::with_capacity(commits.len()); - for log in commits { - indexed_commits.push((Self::batch_index(&log)?, log)); - } - let mut indexed_reverts = Vec::with_capacity(reverts.len()); - for log in reverts { - indexed_reverts.push((Self::batch_index(&log)?, log)); - } - for (batch_index, log) in indexed_commits { - self.commits.entry(batch_index).or_default().push(log); - } - for (batch_index, log) in indexed_reverts { - self.reverts.entry(batch_index).or_default().push(log); - } - self.indexed_snapshot = Some(IndexedSnapshot { - number: snapshot_number, - hash: snapshot_hash, - }); - Ok(()) - } - - fn resolve_cached(&self, batch_index: u64, canonical_hash: H256) -> Option { - select_canonical_commit( - self.commits.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), - self.reverts.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), - canonical_hash, - ) - } - - pub async fn refresh(&mut self, provider: &P, rollup: Address, snapshot_number: U64, snapshot_hash: H256) -> Result<()> { - let before = provider - .get_block(snapshot_number) - .await? - .ok_or_else(|| eyre!("snapshot block {} not found", snapshot_number))?; - if before.hash != Some(snapshot_hash) { - return Err(eyre!("finalized snapshot hash changed before canonical log refresh")); - } - - if let Some(indexed) = self.indexed_snapshot { - let anchor = provider - .get_block(U64::from(indexed.number)) - .await? - .ok_or_else(|| eyre!("canonical log index anchor block disappeared"))?; - let anchor_hash = anchor.hash.ok_or_else(|| eyre!("canonical log index anchor has no hash"))?; - self.verify_cached_anchor(anchor_hash)?; - } - - let query_start = match self.query_start(snapshot_number.as_u64()) { - Ok(query_start) => query_start, - Err(error) => { - self.clear(); - return Err(error); - } - }; - let Some(mut from) = query_start else { - self.verify_cached_anchor(snapshot_hash)?; - return Ok(()); - }; - - let commit_topic = H256::from(keccak256("CommitBatch(uint256,bytes32)")); - let revert_topic = H256::from(keccak256("RevertBatch(uint256,bytes32)")); - let mut commits = Vec::new(); - let mut reverts = Vec::new(); - while from <= snapshot_number.as_u64() { - let to = from.saturating_add(QUERY_RANGE - 1).min(snapshot_number.as_u64()); - let base = Filter::new().address(rollup).from_block(from).to_block(to); - commits.extend(provider.get_logs(&base.clone().topic0(commit_topic)).await?); - reverts.extend(provider.get_logs(&base.topic0(revert_topic)).await?); - if to == snapshot_number.as_u64() { - break; - } - from = to.checked_add(1).ok_or_else(|| eyre!("canonical log query block overflow"))?; - } - - let after = provider - .get_block(snapshot_number) - .await? - .ok_or_else(|| eyre!("snapshot block {} disappeared", snapshot_number))?; - if after.hash != Some(snapshot_hash) { - return Err(eyre!("snapshot block hash changed during canonical log refresh")); - } - - self.append_logs(snapshot_number.as_u64(), snapshot_hash, commits, reverts) - } - - pub async fn resolve( - &self, - rollup: &Rollup, - batch_index: u64, - snapshot_number: U64, - snapshot_hash: H256, - ) -> Result> { - if self.indexed_snapshot - != Some(IndexedSnapshot { - number: snapshot_number.as_u64(), - hash: snapshot_hash, - }) - { - return Err(eyre!("canonical log index is not anchored to the requested snapshot")); - } - let block_id = BlockId::Number(BlockNumber::Number(snapshot_number)); - let canonical_hash: H256 = rollup.committed_batches(U256::from(batch_index)).block(block_id).call().await?.into(); - if canonical_hash.is_zero() { - return Ok(None); - } - Ok(self.resolve_cached(batch_index, canonical_hash)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn batch_log(batch: u64, block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { - Log { - block_number: Some(block.into()), - transaction_index: Some(tx.into()), - log_index: Some(index.into()), - transaction_hash: Some(H256::from_low_u64_be(marker)), - block_hash: Some(H256::from_low_u64_be(block)), - topics: vec![H256::zero(), H256::from_low_u64_be(batch), hash], - ..Default::default() - } - } - - fn log(block: u64, tx: u64, index: u64, hash: H256, marker: u64) -> Log { - batch_log(7, block, tx, index, hash, marker) - } - - #[test] - fn rejects_short_and_unknown_calldata() { - assert!(decode_batch_data_input(&[]).is_err()); - assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - } - - #[test] - fn decodes_shared_pre_and_post_submitter_fixtures() { - let corpus: serde_json::Value = - serde_json::from_str(include_str!("../../../../node/derivation/testdata/rollup_calldata_fixtures.json")).unwrap(); - let mut decoded_count = 0; - for fixture in corpus["fixtures"].as_array().unwrap() { - let epoch = fixture["epoch"].as_str().unwrap(); - if epoch != "pre-submitter" && epoch != "current" { - continue; - } - let data = ethers::utils::hex::decode(fixture["data"].as_str().unwrap().trim_start_matches("0x")).unwrap(); - let decoded = decode_batch_data_input(&data).unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); - assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); - assert_eq!(decoded.last_block_number, fixture["expected"]["lastBlockNumber"].as_u64().unwrap()); - decoded_count += 1; - } - assert_eq!(decoded_count, 6); - } - - #[test] - fn same_hash_recommit_after_revert_is_selected_by_identity() { - let hash = H256::from_low_u64_be(99); - let resolved = select_canonical_commit(&[log(10, 0, 0, hash, 1), log(12, 0, 0, hash, 3)], &[log(11, 0, 0, hash, 2)], hash).unwrap(); - assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); - } - - #[test] - fn zero_hash_and_same_block_revert_order_fail_closed() { - let hash = H256::from_low_u64_be(99); - assert!(select_canonical_commit(&[log(10, 0, 0, hash, 1)], &[], H256::zero()).is_none()); - - let before_revert = log(10, 0, 1, hash, 1); - let revert = log(10, 0, 2, hash, 2); - assert!(select_canonical_commit(&[before_revert], std::slice::from_ref(&revert), hash).is_none()); - - let after_revert = log(10, 0, 3, hash, 3); - let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); - assert_eq!(resolved.transaction_hash, H256::from_low_u64_be(3)); - } - - #[test] - fn compatibility_words_reject_malformed_authority_and_ignore_legacy_bitmap_type() { - let address = Address::from_low_u64_be(7); - let mut address_word = [0u8; 32]; - address_word[12..].copy_from_slice(address.as_bytes()); - assert_eq!(decode_address_word(&address_word).unwrap(), address); - assert!(decode_address_word(&address_word[..31]).is_err()); - address_word[0] = 1; - assert!(decode_address_word(&address_word).is_err()); - - let mut old_tuple = [0u8; 128]; - U256::from(123).to_big_endian(&mut old_tuple[64..96]); - old_tuple[96..128].fill(0xff); // legacy uint256 bitmap, not an ABI address - assert_eq!(decode_batch_data_store_block_number(&old_tuple).unwrap(), U256::from(123)); - assert!(decode_batch_data_store_block_number(&old_tuple[..127]).is_err()); - } - - #[test] - fn canonical_log_index_reuses_snapshot_and_only_plans_new_suffix() { - let snapshot_hash = H256::from_low_u64_be(100); - let mut index = CanonicalLogIndex::new(5).unwrap(); - assert_eq!(index.query_start(10).unwrap(), Some(5)); - - let hash7 = H256::from_low_u64_be(7); - let hash8 = H256::from_low_u64_be(8); - index - .append_logs( - 10, - snapshot_hash, - vec![batch_log(7, 7, 0, 0, hash7, 7), batch_log(8, 8, 0, 0, hash8, 8)], - vec![], - ) - .unwrap(); - - assert!(index.resolve_cached(7, hash7).is_some()); - assert!(index.resolve_cached(8, hash8).is_some()); - assert_eq!(index.query_start(10).unwrap(), None); - assert_eq!(index.query_start(12).unwrap(), Some(11)); - - let hash9 = H256::from_low_u64_be(9); - index - .append_logs(12, H256::from_low_u64_be(102), vec![batch_log(9, 11, 0, 0, hash9, 9)], vec![]) - .unwrap(); - assert!(index.resolve_cached(7, hash7).is_some()); - assert!(index.resolve_cached(9, hash9).is_some()); - } - - #[test] - fn canonical_log_index_discards_cache_and_fails_closed_on_anchor_reorg() { - let old_hash = H256::from_low_u64_be(100); - let mut index = CanonicalLogIndex::new(5).unwrap(); - index - .append_logs(10, old_hash, vec![batch_log(7, 7, 0, 0, H256::from_low_u64_be(7), 7)], vec![]) - .unwrap(); - - let error = index.verify_cached_anchor(H256::from_low_u64_be(101)).unwrap_err(); - assert!(error.to_string().contains("cache discarded")); - assert!(index.resolve_cached(7, H256::from_low_u64_be(7)).is_none()); - assert_eq!(index.query_start(12).unwrap(), Some(5)); - } -} diff --git a/prover/bin/challenge/src/util.rs b/prover/bin/challenge/src/util.rs index d48aa397f..3cfb7432c 100644 --- a/prover/bin/challenge/src/util.rs +++ b/prover/bin/challenge/src/util.rs @@ -47,7 +47,6 @@ pub fn read_parse_env(var_name: &'static str) -> T { } #[tokio::test] -#[ignore = "requires HANDLER_PROVER_RPC and an external prover service"] async fn test_call_prover() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); dotenv::dotenv().ok(); diff --git a/prover/bin/shadow-prove/.env.dev b/prover/bin/shadow-prove/.env.dev index 4900af649..25b52d157 100644 --- a/prover/bin/shadow-prove/.env.dev +++ b/prover/bin/shadow-prove/.env.dev @@ -4,10 +4,7 @@ SHADOW_PROVING_L2_RPC = "http://localhost:8545" SHADOW_PROVING_PROVER_RPC ="http://localhost:3030" SHADOW_PROVING_L1_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" SHADOW_PROVING_L1_SHADOW_ROLLUP = "0x5FbDB2315678afecb367f032d93F642f64180aa3" -# Development fixture only. Production must use the archived Rollup proxy -# deployment block from the deployment manifest. -SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK = 1 SHADOW_PROVING_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" SHADOW_PROVING_MAX_TXN = 600 SHADOW_PROVING_MAX_BLOCK = 300 -SHADOW_PROVING_BATCH_INTERVAL = 7200 +SHADOW_PROVING_BATCH_INTERVAL = 7200 \ No newline at end of file diff --git a/prover/bin/shadow-prove/abi/Rollup.json b/prover/bin/shadow-prove/abi/Rollup.json index e9da0e250..e32ca8619 100644 --- a/prover/bin/shadow-prove/abi/Rollup.json +++ b/prover/bin/shadow-prove/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +383,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +460,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,6 +656,28 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" } ], "name": "commitBatch", @@ -745,68 +729,40 @@ "name": "batchDataInput", "type": "tuple" }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" + "internalType": "bytes", + "name": "signature", + "type": "bytes" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" } ], - "name": "commitState", + "name": "commitBatchWithProof", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -924,7 +880,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -984,19 +940,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +978,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1100,25 +1056,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "pendingBatchCount", - "outputs": [ - { - "internalType": "uint256", - "name": "count", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proofRewardPercent", @@ -1271,19 +1208,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1398,4 +1322,4 @@ "stateMutability": "payable", "type": "receive" } -] +] \ No newline at end of file diff --git a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/prover/bin/shadow-prove/src/abi.rs b/prover/bin/shadow-prove/src/abi.rs index 17a583a48..d98d7b99d 100644 --- a/prover/bin/shadow-prove/src/abi.rs +++ b/prover/bin/shadow-prove/src/abi.rs @@ -7,16 +7,6 @@ sol!( "abi/Rollup.json" ); -// Immutable production ABI from immediately before the Submitter cutover. -// Keep it in a namespace of its own because both ABI snapshots contain an -// `IRollup.BatchDataInput` internal type. -pub mod pre_submitter { - use alloy_sol_types::sol; - - sol!(PreSubmitterRollup, "abi/pre_submitter/Rollup.json"); -} -pub use pre_submitter::PreSubmitterRollup; - sol!( #[sol(rpc)] ShadowRollup, diff --git a/prover/bin/shadow-prove/src/execute.rs b/prover/bin/shadow-prove/src/execute.rs index b063b747f..1a5142e6e 100644 --- a/prover/bin/shadow-prove/src/execute.rs +++ b/prover/bin/shadow-prove/src/execute.rs @@ -124,7 +124,6 @@ mod tests { // cargo test -p shadow-proving --lib -- execute::tests::test_execute_range --exact --nocapture -- --start-block 0x35 --end-block 0x36 --rpc http://127.0.0.1:9545 #[test] - #[ignore = "requires an external L2 RPC and explicit CLI fixture arguments"] fn test_execute_range() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); @@ -139,7 +138,6 @@ mod tests { // cargo test -p shadow-proving --lib -- execute::tests::test_execute_block --exact --nocapture -- --block-number 19997 --rpc http://127.0.0.1:9545 #[tokio::test(flavor = "multi_thread")] - #[ignore = "requires an external L2 RPC and explicit CLI fixture arguments"] async fn test_execute_block() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); @@ -154,7 +152,6 @@ mod tests { } #[tokio::test] - #[ignore = "requires a local L2 RPC fixture"] async fn test_execute_batch() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let handle = tokio::spawn(async move { @@ -174,7 +171,6 @@ mod tests { handle.await.unwrap(); } #[tokio::test] - #[ignore = "requires a local L2 RPC fixture"] async fn test_execute_remote() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let provider = @@ -188,10 +184,8 @@ mod tests { println!("batch_info.post_state_root: {:?}", batch_info.post_state_root); } - // cargo test --package shadow-proving --lib -- execute::tests::test_execute_local --exact - // --nocapture + // cargo test --package shadow-proving --lib -- execute::tests::test_execute_local --exact --nocapture #[tokio::test] - #[ignore = "requires pre-generated local executor fixtures"] async fn test_execute_local() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let dir = "../../testdata/state"; @@ -215,7 +209,6 @@ mod tests { } #[tokio::test] - #[ignore = "requires a production L2 RPC and writes a local fixture"] async fn execute_batch_input() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let provider = ProviderBuilder::new() @@ -266,7 +259,6 @@ mod tests { } #[tokio::test] - #[ignore = "requires a pre-generated local executor fixture"] async fn execute_batch_input_local() { env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); let file = File::open("proof/shadow_input.json").unwrap(); diff --git a/prover/bin/shadow-prove/src/lib.rs b/prover/bin/shadow-prove/src/lib.rs index 3766143bf..62e485968 100644 --- a/prover/bin/shadow-prove/src/lib.rs +++ b/prover/bin/shadow-prove/src/lib.rs @@ -8,7 +8,6 @@ use crate::util::read_env_var; pub mod abi; pub mod execute; pub mod metrics; -pub mod rollup_compat; pub mod shadow_prove; pub mod shadow_rollup; pub mod util; diff --git a/prover/bin/shadow-prove/src/main.rs b/prover/bin/shadow-prove/src/main.rs index e31d1139b..a6cf82946 100644 --- a/prover/bin/shadow-prove/src/main.rs +++ b/prover/bin/shadow-prove/src/main.rs @@ -22,10 +22,8 @@ use shadow_proving::{ SHADOW_PROVING_MAX_TXN, SHADOW_PROVING_PROVER_RPC, }; -use tokio::{ - sync::broadcast, - time::{interval, sleep, MissedTickBehavior}, -}; +use tokio::time::{interval, sleep}; +use tokio::{sync::broadcast, time::MissedTickBehavior}; #[tokio::main] async fn main() { @@ -159,7 +157,6 @@ fn init_shadow_proving( let private_key: String = read_parse_env("SHADOW_PROVING_PRIVATE_KEY"); let rollup: String = read_parse_env("SHADOW_PROVING_L1_ROLLUP"); let shadow_rollup: String = read_parse_env("SHADOW_PROVING_L1_SHADOW_ROLLUP"); - let rollup_deployed_block: u64 = read_parse_env("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK"); let signer: PrivateKeySigner = private_key.parse().expect("parse PrivateKeySigner"); let wallet: EthereumWallet = EthereumWallet::from(signer.clone()); @@ -182,7 +179,6 @@ fn init_shadow_proving( l1_provider.clone(), l2_provider.clone(), l1_signer.clone(), - rollup_deployed_block, ); let shadow_prover = ShadowProver::new( @@ -309,14 +305,12 @@ fn log_format( } #[tokio::test] -#[ignore = "requires the full configured shadow-proving environment"] async fn test_shadow() { dotenv().ok(); env_logger::Builder::new().filter_level(log::LevelFilter::Info).format_target(false).init(); log::info!("Starting shadow proving..."); - // cargo test -p shadow-proving --bin shadow-proving -- test_shadow --exact --nocapture -- - // --batch-num 100 --no-prove + // cargo test -p shadow-proving --bin shadow-proving -- test_shadow --exact --nocapture -- --batch-num 100 --no-prove let (batch_num, prove) = test_args::read_shadow_test_args_from_argv(); let (batch_syncer, shadow_prover, l2_provider) = init_shadow_proving(); diff --git a/prover/bin/shadow-prove/src/rollup_compat.rs b/prover/bin/shadow-prove/src/rollup_compat.rs deleted file mode 100644 index 992eb2f09..000000000 --- a/prover/bin/shadow-prove/src/rollup_compat.rs +++ /dev/null @@ -1,554 +0,0 @@ -use std::collections::HashMap; - -use alloy_primitives::{Bytes, TxHash, B256, U256}; -use alloy_provider::{DynProvider, Provider}; -use alloy_rpc_types::{BlockId, BlockNumberOrTag, Log}; -use alloy_sol_types::SolCall; -use anyhow::{anyhow, Result}; - -use crate::abi::{ - pre_submitter::IRollup as PreSubmitterIRollup, IRollup, PreSubmitterRollup, Rollup, - Rollup::RollupInstance, -}; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum SubmissionKind { - CommitBatch, - CommitState, - CommitBatchWithProof, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BatchDataInput { - pub version: u8, - pub parent_batch_header: Bytes, - pub last_block_number: u64, - pub num_l1_messages: u16, - pub prev_state_root: [u8; 32], - pub post_state_root: [u8; 32], - pub withdrawal_root: [u8; 32], - pub kind: SubmissionKind, - pub pre_submitter: bool, -} - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct LogIdentity { - pub block_number: u64, - pub transaction_index: u64, - pub log_index: u64, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CanonicalCommit { - pub identity: LogIdentity, - pub transaction_hash: TxHash, - pub block_hash: B256, - pub batch_hash: B256, -} - -fn log_identity(log: &Log) -> Option { - Some(LogIdentity { - block_number: log.block_number?, - transaction_index: log.transaction_index?, - log_index: log.log_index?, - }) -} - -/// Select the last canonical Commit after the last Revert at one fixed L1 -/// snapshot. Full log identity (rather than batch hash alone) deliberately -/// distinguishes a same-hash recommit. -pub fn select_canonical_commit( - commits: &[Log], - reverts: &[Log], - canonical_hash: B256, -) -> Option { - if canonical_hash == B256::ZERO { - return None; - } - - let last_revert = reverts.iter().filter(|log| !log.removed).filter_map(log_identity).max(); - - commits - .iter() - .filter(|log| !log.removed) - .filter_map(|log| { - let identity = log_identity(log)?; - if last_revert.is_some_and(|revert| identity <= revert) { - return None; - } - let topics = log.topics(); - if topics.len() < 3 || topics[2] != canonical_hash { - return None; - } - Some(CanonicalCommit { - identity, - transaction_hash: log.transaction_hash?, - block_hash: log.block_hash?, - batch_hash: topics[2], - }) - }) - .max_by_key(|commit| commit.identity) -} - -const LOG_QUERY_BLOCK_RANGE: u64 = 10_000; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -struct IndexedSnapshot { - number: u64, - hash: B256, -} - -/// A reusable Commit/Revert index anchored to one canonical finalized block. -/// -/// The first refresh replays from the configured Rollup deployment block. A -/// later refresh first verifies the previous anchor and then scans only the -/// newly finalized suffix. If the anchor changed, the cache is discarded and -/// the current operation fails closed; a later poll may rebuild from genesis. -#[derive(Debug)] -pub struct CanonicalLogIndex { - rollup_deployed_block: u64, - indexed_snapshot: Option, - commits: HashMap>, - reverts: HashMap>, -} - -impl CanonicalLogIndex { - pub fn new(rollup_deployed_block: u64) -> Result { - if rollup_deployed_block == 0 { - return Err(anyhow!("Rollup deployment block must be non-zero")); - } - Ok(Self { - rollup_deployed_block, - indexed_snapshot: None, - commits: HashMap::new(), - reverts: HashMap::new(), - }) - } - - fn clear(&mut self) { - self.indexed_snapshot = None; - self.commits.clear(); - self.reverts.clear(); - } - - fn query_start(&self, snapshot_number: u64) -> Result> { - if snapshot_number < self.rollup_deployed_block { - return Err(anyhow!( - "Rollup deployment block {} is newer than snapshot {snapshot_number}", - self.rollup_deployed_block - )); - } - match self.indexed_snapshot { - None => Ok(Some(self.rollup_deployed_block)), - Some(indexed) if snapshot_number < indexed.number => Err(anyhow!( - "finalized snapshot moved backwards: indexed={}, requested={snapshot_number}", - indexed.number - )), - Some(indexed) if snapshot_number == indexed.number => Ok(None), - Some(indexed) => Ok(Some( - indexed - .number - .checked_add(1) - .ok_or_else(|| anyhow!("canonical log index block overflow"))?, - )), - } - } - - fn verify_cached_anchor(&mut self, observed_hash: B256) -> Result<()> { - let Some(indexed) = self.indexed_snapshot else { - return Ok(()); - }; - if indexed.hash != observed_hash { - self.clear(); - return Err(anyhow!( - "canonical log index anchor changed at block {}; cache discarded", - indexed.number - )); - } - Ok(()) - } - - fn batch_index(log: &Log) -> Result { - if log.removed { - return Err(anyhow!("removed log returned for finalized canonical range")); - } - // Require every component used by canonical identity before admitting a - // log to the cache. Resolution must never silently skip malformed RPC - // results and fall back to an older Commit. - log_identity(log).ok_or_else(|| anyhow!("canonical Rollup log has incomplete identity"))?; - if log.transaction_hash.is_none() || log.block_hash.is_none() { - return Err(anyhow!("canonical Rollup log has incomplete block/transaction identity")); - } - let topics = log.topics(); - if topics.len() < 3 { - return Err(anyhow!("canonical Rollup log is missing indexed topics")); - } - let batch_index = U256::from_be_slice(topics[1].as_slice()); - if batch_index > U256::from(u64::MAX) { - return Err(anyhow!("Rollup batch index exceeds u64")); - } - Ok(batch_index.to::()) - } - - fn append_logs( - &mut self, - snapshot_number: u64, - snapshot_hash: B256, - commits: Vec, - reverts: Vec, - ) -> Result<()> { - let mut indexed_commits = Vec::with_capacity(commits.len()); - for log in commits { - indexed_commits.push((Self::batch_index(&log)?, log)); - } - let mut indexed_reverts = Vec::with_capacity(reverts.len()); - for log in reverts { - indexed_reverts.push((Self::batch_index(&log)?, log)); - } - for (batch_index, log) in indexed_commits { - self.commits.entry(batch_index).or_default().push(log); - } - for (batch_index, log) in indexed_reverts { - self.reverts.entry(batch_index).or_default().push(log); - } - self.indexed_snapshot = - Some(IndexedSnapshot { number: snapshot_number, hash: snapshot_hash }); - Ok(()) - } - - fn resolve_cached(&self, batch_index: u64, canonical_hash: B256) -> Option { - select_canonical_commit( - self.commits.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), - self.reverts.get(&batch_index).map(Vec::as_slice).unwrap_or_default(), - canonical_hash, - ) - } - - pub async fn refresh( - &mut self, - provider: &DynProvider, - rollup: &RollupInstance, - snapshot_number: u64, - snapshot_hash: B256, - ) -> Result<()> { - let snapshot_tag = BlockNumberOrTag::Number(snapshot_number); - let before = provider - .get_block_by_number(snapshot_tag) - .await? - .ok_or_else(|| anyhow!("snapshot block {snapshot_number} not found"))?; - if before.header.hash != snapshot_hash { - return Err(anyhow!("finalized snapshot hash changed before canonical log refresh")); - } - - if let Some(indexed) = self.indexed_snapshot { - let anchor = provider - .get_block_by_number(BlockNumberOrTag::Number(indexed.number)) - .await? - .ok_or_else(|| anyhow!("canonical log index anchor block disappeared"))?; - self.verify_cached_anchor(anchor.header.hash)?; - } - - let query_start = match self.query_start(snapshot_number) { - Ok(query_start) => query_start, - Err(error) => { - self.clear(); - return Err(error); - } - }; - let Some(mut from) = query_start else { - // Equal-height reuse still verifies the caller supplied the exact - // cached block hash, rather than merely the block number. - self.verify_cached_anchor(snapshot_hash)?; - return Ok(()); - }; - - let mut commits = Vec::new(); - let mut reverts = Vec::new(); - while from <= snapshot_number { - let to = from.saturating_add(LOG_QUERY_BLOCK_RANGE - 1).min(snapshot_number); - let commit_filter = rollup - .CommitBatch_filter() - .filter - .from_block(from) - .to_block(to) - .address(*rollup.address()); - commits.extend(provider.get_logs(&commit_filter).await?); - - let revert_filter = rollup - .RevertBatch_filter() - .filter - .from_block(from) - .to_block(to) - .address(*rollup.address()); - reverts.extend(provider.get_logs(&revert_filter).await?); - - if to == snapshot_number { - break; - } - from = - to.checked_add(1).ok_or_else(|| anyhow!("canonical log query block overflow"))?; - } - - let after = provider - .get_block_by_number(snapshot_tag) - .await? - .ok_or_else(|| anyhow!("snapshot block {snapshot_number} disappeared"))?; - if after.header.hash != snapshot_hash { - return Err(anyhow!("snapshot block hash changed during canonical log refresh")); - } - - self.append_logs(snapshot_number, snapshot_hash, commits, reverts) - } - - /// Resolve from the already-refreshed fixed snapshot. Multiple batch - /// lookups (shadow prev/current/next) reuse the same log replay. - pub async fn resolve( - &self, - rollup: &RollupInstance, - batch_index: u64, - snapshot_number: u64, - snapshot_hash: B256, - ) -> Result> { - if self.indexed_snapshot != - Some(IndexedSnapshot { number: snapshot_number, hash: snapshot_hash }) - { - return Err(anyhow!("canonical log index is not anchored to the requested snapshot")); - } - let canonical_hash = rollup - .committedBatches(U256::from(batch_index)) - .block(BlockId::Number(BlockNumberOrTag::Number(snapshot_number))) - .call() - .await?; - if canonical_hash == B256::ZERO { - return Ok(None); - } - Ok(self.resolve_cached(batch_index, canonical_hash)) - } -} - -fn current_input(input: IRollup::BatchDataInput, kind: SubmissionKind) -> BatchDataInput { - BatchDataInput { - version: input.version, - parent_batch_header: input.parentBatchHeader, - last_block_number: input.lastBlockNumber, - num_l1_messages: input.numL1Messages, - prev_state_root: *input.prevStateRoot, - post_state_root: *input.postStateRoot, - withdrawal_root: *input.withdrawalRoot, - kind, - pre_submitter: false, - } -} - -fn historical_input( - input: PreSubmitterIRollup::BatchDataInput, - kind: SubmissionKind, -) -> BatchDataInput { - BatchDataInput { - version: input.version, - parent_batch_header: input.parentBatchHeader, - last_block_number: input.lastBlockNumber, - num_l1_messages: input.numL1Messages, - prev_state_root: *input.prevStateRoot, - post_state_root: *input.postStateRoot, - withdrawal_root: *input.withdrawalRoot, - kind, - pre_submitter: true, - } -} - -/// Decode only the first `BatchDataInput` argument from every submission ABI -/// supported across the Submitter cutover. Unknown and short selectors fail -/// closed; historical signature data is intentionally not exposed. -pub fn decode_batch_data_input(data: &[u8]) -> Result { - if data.len() < 4 { - return Err(anyhow!("rollup calldata is shorter than a selector")); - } - - if let Ok(call) = Rollup::commitBatchCall::abi_decode(data) { - return Ok(current_input(call.batchDataInput, SubmissionKind::CommitBatch)); - } - if let Ok(call) = Rollup::commitStateCall::abi_decode(data) { - return Ok(current_input(call.batchDataInput, SubmissionKind::CommitState)); - } - if let Ok(call) = Rollup::commitBatchWithProofCall::abi_decode(data) { - return Ok(current_input(call.batchDataInput, SubmissionKind::CommitBatchWithProof)); - } - - if let Ok(call) = PreSubmitterRollup::commitBatchCall::abi_decode(data) { - return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitBatch)); - } - if let Ok(call) = PreSubmitterRollup::commitStateCall::abi_decode(data) { - return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitState)); - } - if let Ok(call) = PreSubmitterRollup::commitBatchWithProofCall::abi_decode(data) { - return Ok(historical_input(call.batchDataInput, SubmissionKind::CommitBatchWithProof)); - } - - Err(anyhow!("unsupported rollup submission selector")) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_primitives::{Address, Log as PrimitiveLog}; - - fn rpc_log( - batch_index: u64, - batch_hash: B256, - block_number: u64, - transaction_index: u64, - log_index: u64, - tx_marker: u8, - ) -> Log { - Log { - inner: PrimitiveLog::new_unchecked( - Address::ZERO, - vec![ - B256::ZERO, - B256::from(U256::from(batch_index).to_be_bytes::<32>()), - batch_hash, - ], - Bytes::new(), - ), - block_number: Some(block_number), - transaction_index: Some(transaction_index), - log_index: Some(log_index), - transaction_hash: Some(B256::repeat_byte(tx_marker)), - block_hash: Some(B256::repeat_byte(block_number as u8)), - ..Default::default() - } - } - - #[test] - fn rejects_short_and_unknown_calldata() { - assert!(decode_batch_data_input(&[]).is_err()); - assert!(decode_batch_data_input(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - } - - #[test] - fn decodes_shared_pre_and_post_submitter_fixtures() { - let corpus: serde_json::Value = serde_json::from_str(include_str!( - "../../../../node/derivation/testdata/rollup_calldata_fixtures.json" - )) - .unwrap(); - let mut decoded_count = 0; - for fixture in corpus["fixtures"].as_array().unwrap() { - let epoch = fixture["epoch"].as_str().unwrap(); - if epoch != "pre-submitter" && epoch != "current" { - continue; - } - let data = alloy_primitives::hex::decode( - fixture["data"].as_str().unwrap().trim_start_matches("0x"), - ) - .unwrap(); - let decoded = decode_batch_data_input(&data) - .unwrap_or_else(|err| panic!("{}: {err:#}", fixture["name"])); - assert_eq!(decoded.version as u64, fixture["expected"]["version"].as_u64().unwrap()); - assert_eq!( - decoded.last_block_number, - fixture["expected"]["lastBlockNumber"].as_u64().unwrap() - ); - decoded_count += 1; - } - assert_eq!(decoded_count, 6); - } - - #[test] - fn selector_sets_are_distinct() { - assert_eq!(Rollup::commitBatchCall::SELECTOR, [0x41, 0xf7, 0x56, 0xda]); - assert_eq!(Rollup::commitStateCall::SELECTOR, [0x67, 0xca, 0xa3, 0x7a]); - assert_eq!(Rollup::commitBatchWithProofCall::SELECTOR, [0x15, 0x44, 0xba, 0x3a]); - - assert_eq!(PreSubmitterRollup::commitBatchCall::SELECTOR, [0x42, 0x88, 0x68, 0xb5]); - assert_eq!(PreSubmitterRollup::commitStateCall::SELECTOR, [0x1e, 0x88, 0x25, 0xbe]); - assert_eq!( - PreSubmitterRollup::commitBatchWithProofCall::SELECTOR, - [0x4e, 0x8f, 0x1d, 0x67] - ); - } - - #[test] - fn recommit_after_revert_wins_even_when_hash_is_identical() { - let hash = B256::repeat_byte(0x44); - let first = rpc_log(7, hash, 10, 0, 0, 1); - let revert = rpc_log(7, hash, 11, 0, 0, 2); - let second = rpc_log(7, hash, 12, 0, 0, 3); - - let resolved = select_canonical_commit(&[first, second], &[revert], hash).unwrap(); - assert_eq!(resolved.transaction_hash, B256::repeat_byte(3)); - assert_eq!(resolved.identity.block_number, 12); - } - - #[test] - fn zero_hash_and_same_block_revert_order_fail_closed() { - let hash = B256::repeat_byte(0x44); - assert!( - select_canonical_commit(&[rpc_log(7, hash, 10, 0, 0, 1)], &[], B256::ZERO).is_none() - ); - - let before_revert = rpc_log(7, hash, 10, 0, 1, 1); - let revert = rpc_log(7, hash, 10, 0, 2, 2); - assert!(select_canonical_commit(&[before_revert], std::slice::from_ref(&revert), hash) - .is_none()); - - let after_revert = rpc_log(7, hash, 10, 0, 3, 3); - let resolved = select_canonical_commit(&[after_revert], &[revert], hash).unwrap(); - assert_eq!(resolved.transaction_hash, B256::repeat_byte(3)); - } - - #[test] - fn canonical_log_index_reuses_one_snapshot_for_adjacent_batches_and_then_increments() { - let snapshot_hash = B256::repeat_byte(0xaa); - let mut index = CanonicalLogIndex::new(5).unwrap(); - assert_eq!(index.query_start(10).unwrap(), Some(5)); - - let hash6 = B256::repeat_byte(6); - let hash7 = B256::repeat_byte(7); - let hash8 = B256::repeat_byte(8); - index - .append_logs( - 10, - snapshot_hash, - vec![ - rpc_log(6, hash6, 6, 0, 0, 6), - rpc_log(7, hash7, 7, 0, 0, 7), - rpc_log(8, hash8, 8, 0, 0, 8), - ], - vec![], - ) - .unwrap(); - - // prev/current/next are all served by the same indexed replay. - assert_eq!(index.resolve_cached(6, hash6).unwrap().identity.block_number, 6); - assert_eq!(index.resolve_cached(7, hash7).unwrap().identity.block_number, 7); - assert_eq!(index.resolve_cached(8, hash8).unwrap().identity.block_number, 8); - assert_eq!(index.query_start(10).unwrap(), None); - assert_eq!(index.query_start(12).unwrap(), Some(11)); - - index - .append_logs( - 12, - B256::repeat_byte(0xbb), - vec![rpc_log(9, B256::repeat_byte(9), 11, 0, 0, 9)], - vec![], - ) - .unwrap(); - assert!(index.resolve_cached(7, hash7).is_some()); - assert!(index.resolve_cached(9, B256::repeat_byte(9)).is_some()); - } - - #[test] - fn canonical_log_index_discards_cache_and_fails_closed_on_anchor_reorg() { - let old_hash = B256::repeat_byte(0xaa); - let mut index = CanonicalLogIndex::new(5).unwrap(); - index - .append_logs(10, old_hash, vec![rpc_log(7, B256::repeat_byte(7), 7, 0, 0, 7)], vec![]) - .unwrap(); - - let error = index.verify_cached_anchor(B256::repeat_byte(0xbb)).unwrap_err(); - assert!(error.to_string().contains("cache discarded")); - assert!(index.resolve_cached(7, B256::repeat_byte(7)).is_none()); - assert_eq!(index.query_start(12).unwrap(), Some(5)); - } -} diff --git a/prover/bin/shadow-prove/src/shadow_prove.rs b/prover/bin/shadow-prove/src/shadow_prove.rs index cd0dee8cd..ad53a2e76 100644 --- a/prover/bin/shadow-prove/src/shadow_prove.rs +++ b/prover/bin/shadow-prove/src/shadow_prove.rs @@ -39,8 +39,7 @@ mod task_status { pub const PROVED: &str = "Proved"; } -// ShadowProver is responsible for proving the batch state onchain through the shadow rollup -// contract. +// ShadowProver is responsible for proving the batch state onchain through the shadow rollup contract. #[derive(Clone, Debug)] pub struct ShadowProver { shadow_provider: DynProvider, @@ -285,24 +284,14 @@ async fn query_proof(batch_index: u64) -> Option { fn test() { use crate::abi::SP1Verifier; use alloy_json_rpc::ErrorPayload; - use alloy_primitives::hex; - use alloy_sol_types::SolError; - - let expected_error = SP1Verifier::WrongVerifierSelector { - received: [0, 0, 0, 1].into(), - expected: [0, 0, 0, 2].into(), - }; - let json = format!( - r#"{{"code":3,"message":"execution reverted: ","data":"{}"}}"#, - hex::encode_prefixed(expected_error.abi_encode()) - ); + // Sample JSON error payload from an Ethereum JSON RPC response. + let json = r#"{"code":3,"message":"execution reverted: ","data":"0x810f00230000000000000000000000000000000000000000000000000000000000000001"}"#; // Parse the JSON into an `ErrorPayload` struct. - let payload: ErrorPayload = serde_json::from_str(&json).unwrap(); + let payload: ErrorPayload = serde_json::from_str(json).unwrap(); if let Some(s) = payload.as_decoded_error::() { - assert_eq!(s.expected, expected_error.expected); - assert_eq!(s.received, expected_error.received); + println!("WrongVerifierSelector - expected: {:?}, received: {:?}", s.expected, s.received); } else if payload.as_decoded_error::().is_some() { println!("WrongVerifierSelector"); } else { diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index 5dc88264b..df1f7292c 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -1,17 +1,15 @@ -use crate::{metrics::METRICS, BatchInfo}; +use crate::{metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; use alloy_consensus::Transaction; use alloy_network::{Network, ReceiptResponse}; -use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256}; +use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256, U64}; use alloy_provider::{DynProvider, Provider}; -use alloy_rpc_types::{BlockId, BlockNumberOrTag}; +use alloy_rpc_types::Log; +use alloy_sol_types::SolCall; use anyhow::{anyhow, Context, Result}; use futures::future::join_all; -use std::sync::Arc; -use tokio::sync::Mutex; use crate::{ - rollup_compat::{decode_batch_data_input, BatchDataInput, CanonicalCommit, CanonicalLogIndex}, Rollup::{self, RollupInstance}, ShadowRollup::{self, ShadowRollupInstance}, }; @@ -22,7 +20,6 @@ pub struct BatchSyncer { l2_provider: DynProvider, l1_rollup: RollupInstance, l1_shadow_rollup: ShadowRollupInstance, - canonical_log_index: Arc>, } impl BatchSyncer @@ -30,132 +27,264 @@ where P: Provider + Clone, N: Network, { - async fn finalized_snapshot(&self) -> Result<(u64, B256)> { - let block = self - .l1_provider - .get_block_by_number(BlockNumberOrTag::Finalized) - .await? - .ok_or_else(|| anyhow!("finalized L1 block is unavailable"))?; - Ok((block.header.number, block.header.hash)) - } - - async fn assert_snapshot(&self, number: u64, expected_hash: B256) -> Result<()> { - let block = self - .l1_provider - .get_block_by_number(BlockNumberOrTag::Number(number)) - .await? - .ok_or_else(|| anyhow!("snapshot L1 block {number} is unavailable"))?; - if block.header.hash != expected_hash { - return Err(anyhow!( - "finalized L1 snapshot changed: number={number}, expected={expected_hash:?}, actual={:?}", - block.header.hash - )); - } - Ok(()) - } - pub fn new( rollup_address: Address, shadow_rollup_address: Address, l1_provider: DynProvider, l2_provider: DynProvider, wallet: P, - rollup_deployed_block: u64, ) -> Self { let l1_rollup = Rollup::RollupInstance::new(rollup_address, l1_provider.clone()); let l1_shadow_rollup = ShadowRollup::new(shadow_rollup_address, wallet); - let canonical_log_index = Arc::new(Mutex::new( - CanonicalLogIndex::new(rollup_deployed_block) - .expect("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK must be non-zero"), - )); - Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup, canonical_log_index } + Self { l1_provider, l2_provider, l1_rollup, l1_shadow_rollup } } // Fetch the latest committed batch from l1-rollup if the batch_index has increased. pub async fn get_latest_batch(&self, batch_index: u64) -> Result> { - let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; - let last_committed_batch_index = self - .l1_rollup - .lastCommittedBatchIndex() - .block(BlockId::Number(BlockNumberOrTag::Number(snapshot))) - .call() - .await? - .to::(); - self.assert_snapshot(snapshot, snapshot_hash).await?; - if last_committed_batch_index <= batch_index.saturating_add(1) { + let last_committed_batch_index = self.l1_rollup.lastCommittedBatchIndex().call().await?; + if last_committed_batch_index <= batch_index + 1 { log::info!( "The current batch_index has not increased, latest_batch_index: {last_committed_batch_index:?}" ); return Ok(None); } - if last_committed_batch_index <= 2 { - return Ok(None); - } - self.get_specified_batch_at(last_committed_batch_index - 1, snapshot, snapshot_hash).await + self.get_committed_batch().await } // Fetch the latest committed batch from l1-rollup. pub async fn get_committed_batch(&self) -> Result> { - let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; - let last_committed = self + let latest = match self.l1_provider.get_block_number().await { + Ok(v) => U64::from(v), + Err(e) => { + log::error!("l1_provider.get_block_number error: {:?}", e); + return Err(anyhow!("l1_provider.get_block_number error")); + } + }; + + log::info!("latest l1 blocknum = {:#?}", latest); + let start = if latest > U64::from(*SHADOW_PROVING_BLOCKS_RANGE) { + latest - U64::from(*SHADOW_PROVING_BLOCKS_RANGE) + } else { + U64::from(1) + }; + let filter = self .l1_rollup - .lastCommittedBatchIndex() - .block(BlockId::Number(BlockNumberOrTag::Number(snapshot))) - .call() - .await?; - self.assert_snapshot(snapshot, snapshot_hash).await?; - let last_committed = last_committed.to::(); - if last_committed <= 2 { + .CommitBatch_filter() + .filter + .from_block(start) + .address(*self.l1_rollup.address()); + let mut logs: Vec = match self.l1_provider.get_logs(&filter).await { + Ok(logs) => logs, + Err(e) => { + log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); + return Err(anyhow!("l1_rollup.commit_batch.get_logs provider error")); + } + }; + if logs.is_empty() { + log::warn!("There have been no commit_batch logs for the last 600 blocks"); + return Ok(None); + } + if logs.len() < 3 { + log::warn!("No enough commit_batch logs for the last 600 blocks"); return Ok(None); } + logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); + + let batch_index_hash = match logs.get(logs.len() - 2) { + Some(log) => { + let _index = U256::from_be_slice(log.topics()[1].as_slice()); + (_index.to::(), log.transaction_hash.unwrap_or_default()) + } + None => { + return Err(anyhow!("find commit_batch log error")); + } + }; + + if batch_index_hash.0 == 0 { + return Err(anyhow!("batch_index is 0")); + } - // The next canonical commit carries the target batch header as its - // parentBatchHeader, so prove the newest batch that has a canonical - // successor rather than relying on three adjacent logs. - self.get_specified_batch_at(last_committed - 1, snapshot, snapshot_hash).await + let prev_tx_hash = match logs.get(logs.len() - 3) { + Some(log) => log.transaction_hash.unwrap_or_default(), + None => { + return Err(anyhow!("find commit_batch log error")); + } + }; + + let (blocks, total_txn_count) = + match self.batch_blocks_inspect(prev_tx_hash, batch_index_hash.1).await { + Some(block_txn) => block_txn, + None => return Err(anyhow!("batch_blocks_inspect none")), + }; + + if blocks.0 >= blocks.1 { + return Err(anyhow!("blocks is empty")); + } + + let batch_info: BatchInfo = BatchInfo { + batch_index: batch_index_hash.0, + start_block: blocks.0, + end_block: blocks.1, + total_txn: total_txn_count, + }; + + // A rollup commit_batch_input contains prev batch_header. + let next_tx_hash = match logs.last() { + Some(log) => log.transaction_hash.unwrap_or_default(), + + None => { + return Err(anyhow!("find commit_batch log error")); + } + }; + let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) + .await + .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; + + log::info!("Found the committed batch, batch index = {:#?}", batch_index_hash.0); + Ok(Some((batch_info, batch_input.0))) } /// Fetch a specified batch from l1-rollup by batch_num. pub async fn get_specified_batch(&self, batch_num: u64) -> Result> { - let (snapshot, snapshot_hash) = self.finalized_snapshot().await?; - self.get_specified_batch_at(batch_num, snapshot, snapshot_hash).await - } + use std::collections::{HashMap, HashSet}; - async fn get_specified_batch_at( - &self, - batch_num: u64, - snapshot: u64, - snapshot_hash: B256, - ) -> Result> { - if batch_num <= 1 { + if batch_num == 0 { + return Err(anyhow!("batch_num is 0")); + } + if batch_num == 1 { // We need prev(batch_num-1) to infer start_block, and next(batch_num+1) to retrieve the // specified batch header (via parentBatchHeader). - return Err(anyhow!("batch_num must be greater than 1")); + return Err(anyhow!("batch_num is 1, cannot infer prev batch")); } - self.assert_snapshot(snapshot, snapshot_hash).await?; - let mut canonical_log_index = self.canonical_log_index.lock().await; - canonical_log_index - .refresh(&self.l1_provider, &self.l1_rollup, snapshot, snapshot_hash) - .await?; - let prev = canonical_log_index - .resolve(&self.l1_rollup, batch_num - 1, snapshot, snapshot_hash) - .await?; - let current = canonical_log_index - .resolve(&self.l1_rollup, batch_num, snapshot, snapshot_hash) - .await?; - let next = canonical_log_index - .resolve(&self.l1_rollup, batch_num + 1, snapshot, snapshot_hash) - .await?; - drop(canonical_log_index); - self.assert_snapshot(snapshot, snapshot_hash).await?; - let (Some(prev), Some(current), Some(next)) = (prev, current, next) else { + let last_committed_batch_index = self.l1_rollup.lastCommittedBatchIndex().call().await?; + if last_committed_batch_index <= batch_num { + log::info!( + "last committed batch index {:#?} is less than or equal to the specified batch_num {:#?}", + last_committed_batch_index, + batch_num + ); return Ok(None); + } + + let latest = match self.l1_provider.get_block_number().await { + Ok(v) => U64::from(v), + Err(e) => { + log::error!("l1_provider.get_block_number error: {:?}", e); + return Err(anyhow!("l1_provider.get_block_number error")); + } }; - let ((blocks, total_txn_count), current_input) = - self.batch_blocks_inspect(&prev, ¤t).await?; + log::info!("latest l1 blocknum = {:#?}", latest); + + // Goal: collect (batch_index, tx_hash) for the specified batch and its immediate neighbors. + // - prev: batch_num - 1 (used to infer start_block) + // - curr: batch_num (used to infer end_block) + // - next: batch_num + 1 (commitBatch calldata contains parentBatchHeader == curr header) + let targets: HashSet = [batch_num - 1, batch_num, batch_num + 1].into_iter().collect(); + let mut found: HashMap = HashMap::with_capacity(3); + + let blocks_window = 600u64; + let mut distance_count = 1u64; + loop { + if distance_count > 100 { + return Err(anyhow!( + "Exceeded max distance count when searching commit_batch logs" + )); + } + // Scan backward from `latest` in fixed-size windows until all 3 targets are found. + // Note: alloy filter block numbers are U64; avoid underflow. + let to_block = latest.saturating_sub(U64::from(blocks_window * (distance_count - 1))); + let mut from_block = latest.saturating_sub(U64::from(blocks_window * distance_count)); + if from_block < U64::from(1) { + from_block = U64::from(1); + } + + let filter = self + .l1_rollup + .CommitBatch_filter() + .filter + .from_block(from_block) + .to_block(to_block) + .address(*self.l1_rollup.address()); + + let mut logs: Vec = match self.l1_provider.get_logs(&filter).await { + Ok(logs) => logs, + Err(e) => { + log::error!("l1_rollup.commit_batch.get_logs error: {:#?}", e); + return Err(anyhow!("l1_rollup.commit_batch.get_logs provider error")); + } + }; + if logs.is_empty() { + log::warn!( + "There have been no commit_batch logs for the this {} blocks window (from={:?}, to={:?})", + blocks_window, + from_block, + to_block + ); + } + + logs.sort_by(|a, b| { + a.block_number.unwrap_or_default().cmp(&b.block_number.unwrap_or_default()) + }); + + for log in logs.iter() { + if found.len() == targets.len() { + break; + } + if log.topics().len() < 2 { + continue; + } + let index_u256 = U256::from_be_slice(log.topics()[1].as_slice()); + let idx = index_u256.to::(); + if !targets.contains(&idx) { + continue; + } + // A given batch_index should appear only once; if duplicated events exist, keep the + // first-seen tx_hash. + found.entry(idx).or_insert(log.transaction_hash.unwrap_or_default()); + } + + if found.len() == targets.len() { + break; + } + + // Reached the chain head (block 1) and still not enough logs found. + if from_block == U64::from(1) { + log::warn!( + "Cannot find enough commit_batch logs for batch_num={} (found={:?})", + batch_num, + found.keys().collect::>() + ); + return Ok(None); + } + + distance_count += 1; + } + + // Assemble the triplet in order: prev, curr, next. + let mut batch_index_hash: Vec<(u64, TxHash)> = Vec::with_capacity(3); + for idx in [batch_num - 1, batch_num, batch_num + 1] { + let tx = *found.get(&idx).unwrap_or(&TxHash::ZERO); + if tx == TxHash::ZERO { + return Ok(None); + } + batch_index_hash.push((idx, tx)); + } + + let prev_tx_hash = batch_index_hash[0].1; + let curr_tx_hash = batch_index_hash[1].1; + let next_tx_hash = batch_index_hash[2].1; + + let (blocks, total_txn_count) = + match self.batch_blocks_inspect(prev_tx_hash, curr_tx_hash).await { + Some(block_txn) => block_txn, + None => return Err(anyhow!("batch_blocks_inspect none")), + }; + if blocks.0 >= blocks.1 { + return Err(anyhow!("blocks is empty")); + } let batch_info: BatchInfo = BatchInfo { batch_index: batch_num, @@ -165,34 +294,12 @@ where }; // next(batch_num+1) commitBatch calldata contains curr(batch_num) parentBatchHeader. - let next_input = - canonical_batch_input_inspect(&self.l1_provider, &next, *self.l1_rollup.address()) - .await?; - let batch_header = next_input.parent_batch_header; - validate_canonical_header( - batch_header.as_ref(), - batch_num, - prev.batch_hash, - ¤t_input, - )?; - let mut hasher = Keccak256::new(); - hasher.update(batch_header.as_ref()); - let header_hash = hasher.finalize(); - if header_hash != current.batch_hash { - return Err(anyhow!( - "canonical batch header hash mismatch: event={:?}, calldata={:?}", - current.batch_hash, - header_hash - )); - } - self.assert_snapshot(snapshot, snapshot_hash).await?; + let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) + .await + .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; - log::info!( - "Found canonical specified batch: batch_index={}, commit_identity={:?}", - batch_num, - current.identity - ); - Ok(Some((batch_info, batch_header))) + log::info!("Found the specified batch (prev/curr/next): {:?}", batch_index_hash); + Ok(Some((batch_info, batch_input.0))) } /** @@ -283,30 +390,18 @@ where // Inspect blocks range and total txn count in a batch. async fn batch_blocks_inspect( &self, - prev: &CanonicalCommit, - current: &CanonicalCommit, - ) -> Result<(((u64, u64), u64), BatchDataInput)> { - let rollup_address = *self.l1_rollup.address(); - let prev_batch_input = - canonical_batch_input_inspect(&self.l1_provider, prev, rollup_address).await?; + prev_batch_hash: TxHash, + current_batch_hash: TxHash, + ) -> Option<((u64, u64), u64)> { + let prev_batch_input = batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; let current_batch_input = - canonical_batch_input_inspect(&self.l1_provider, current, rollup_address).await?; - let start_block = prev_batch_input - .last_block_number - .checked_add(1) - .ok_or_else(|| anyhow!("previous batch last block overflows"))?; - let end_block = current_batch_input.last_block_number; + batch_input_inspect(&self.l1_provider, current_batch_hash).await?; + let start_block = prev_batch_input.1 + 1; + let end_block = current_batch_input.1; if start_block == 0 { - return Err(anyhow!( - "batch_blocks_inspect: start_block = 0, tx_hash = {:?}", - prev.transaction_hash - )); - } - if start_block > end_block { - return Err(anyhow!( - "batch_blocks_inspect: invalid block range {start_block}..={end_block}" - )); + log::error!("batch_blocks_inspect: start_block = 0, tx_hash = {:#?}", prev_batch_hash); + return None; } let mut total_tx_count: u64 = 0; @@ -321,9 +416,7 @@ where } let results = join_all(tasks).await; for res in results { - total_tx_count += res - .context("query L2 block transaction count")? - .ok_or_else(|| anyhow!("L2 block transaction count is unavailable"))?; + total_tx_count += res.unwrap_or_default().unwrap_or_default(); } } @@ -336,7 +429,7 @@ where METRICS.shadow_txn_len.set(total_tx_count as i64); - Ok((((start_block, end_block), total_tx_count), current_batch_input)) + Some(((start_block, end_block), total_tx_count)) } // Check whether a batch has been proved successfully. @@ -416,129 +509,17 @@ pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Opt log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let param = match decode_batch_data_input(data) { - Ok(param) => param, - Err(err) => { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); - log::debug!("batch inspect decode error: {err:#}"); - return None; - } + let param = if let Ok(_param) = Rollup::commitBatchCall::abi_decode(data) { + _param + } else { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); + return None; }; - let parent_batch_header = param.parent_batch_header; - let last_block_number = param.last_block_number; + let parent_batch_header: Bytes = param.batchDataInput.parentBatchHeader; + let last_block_number: u64 = param.batchDataInput.lastBlockNumber; Some((parent_batch_header, last_block_number)) } - -async fn canonical_batch_input_inspect( - l1_provider: &DynProvider, - commit: &CanonicalCommit, - rollup_address: Address, -) -> Result { - let tx = l1_provider - .get_transaction_by_hash(commit.transaction_hash) - .await? - .ok_or_else(|| anyhow!("canonical commit transaction is unavailable"))?; - if tx.to() != Some(rollup_address) || - tx.block_number != Some(commit.identity.block_number) || - tx.transaction_index != Some(commit.identity.transaction_index) || - tx.block_hash != Some(commit.block_hash) - { - return Err(anyhow!( - "canonical commit transaction identity mismatch: expected={:?}, tx_block={:?}, tx_index={:?}, tx_block_hash={:?}", - commit.identity, - tx.block_number, - tx.transaction_index, - tx.block_hash - )); - } - decode_batch_data_input(tx.input()) -} - -fn validate_canonical_header( - header: &[u8], - expected_batch_index: u64, - expected_parent_hash: B256, - input: &BatchDataInput, -) -> Result<()> { - let minimum_len = if input.version == 0 { 249 } else { 257 }; - if header.len() < minimum_len { - return Err(anyhow!( - "canonical batch header is too short: version={}, len={}", - input.version, - header.len() - )); - } - if header[0] != input.version { - return Err(anyhow!("canonical batch header version mismatch")); - } - if u64::from_be_bytes(header[1..9].try_into().unwrap()) != expected_batch_index { - return Err(anyhow!("canonical batch header index mismatch")); - } - if header[89..121] != input.prev_state_root || - header[121..153] != input.post_state_root || - header[153..185] != input.withdrawal_root - { - return Err(anyhow!("canonical batch header root mismatch")); - } - if header[217..249] != expected_parent_hash[..] { - return Err(anyhow!("canonical batch header parent hash mismatch")); - } - if input.version > 0 && - u64::from_be_bytes(header[249..257].try_into().unwrap()) != input.last_block_number - { - return Err(anyhow!("canonical batch header last block mismatch")); - } - Ok(()) -} - -#[cfg(test)] -mod canonical_header_tests { - use super::*; - use crate::rollup_compat::SubmissionKind; - - fn fixture() -> (Vec, BatchDataInput, B256) { - let parent_hash = B256::repeat_byte(0x44); - let input = BatchDataInput { - version: 2, - parent_batch_header: Bytes::new(), - last_block_number: 123, - num_l1_messages: 0, - prev_state_root: [0x11; 32], - post_state_root: [0x22; 32], - withdrawal_root: [0x33; 32], - kind: SubmissionKind::CommitBatch, - pre_submitter: false, - }; - let mut header = vec![0u8; 257]; - header[0] = input.version; - header[1..9].copy_from_slice(&7u64.to_be_bytes()); - header[89..121].copy_from_slice(&input.prev_state_root); - header[121..153].copy_from_slice(&input.post_state_root); - header[153..185].copy_from_slice(&input.withdrawal_root); - header[217..249].copy_from_slice(parent_hash.as_slice()); - header[249..257].copy_from_slice(&input.last_block_number.to_be_bytes()); - (header, input, parent_hash) - } - - #[test] - fn canonical_header_matches_calldata_roots_parent_and_range() { - let (header, input, parent_hash) = fixture(); - validate_canonical_header(&header, 7, parent_hash, &input).unwrap(); - } - - #[test] - fn canonical_header_mismatch_fails_closed() { - let (mut header, input, parent_hash) = fixture(); - header[121] ^= 1; - assert!(validate_canonical_header(&header, 7, parent_hash, &input).is_err()); - - let (mut header, input, parent_hash) = fixture(); - header[256] ^= 1; - assert!(validate_canonical_header(&header, 7, parent_hash, &input).is_err()); - } -} #[tokio::test] -#[ignore = "requires configured L1/L2 RPCs and a funded signer"] async fn test_sync_batch() { use alloy_network::EthereumWallet; use alloy_primitives::Address; @@ -565,10 +546,6 @@ async fn test_sync_batch() { let rollup = var("SHADOW_PROVING_L1_ROLLUP").expect("Cannot detect L1_ROLLUP env var"); let shadow_rollup = var("SHADOW_PROVING_L1_SHADOW_ROLLUP").expect("Cannot detect L1_SHADOW_ROLLUP env var"); - let rollup_deployed_block = var("SHADOW_PROVING_L1_ROLLUP_DEPLOY_BLOCK") - .unwrap_or_else(|_| "1".to_string()) - .parse() - .unwrap(); let l1_signer = ProviderBuilder::new().wallet(wallet).connect_http(l1_rpc.parse().unwrap()); @@ -578,14 +555,12 @@ async fn test_sync_batch() { l1_provider, l2_provider, l1_signer, - rollup_deployed_block, ); let batch = bs.get_committed_batch().await.unwrap().unwrap(); bs.sync_batch(batch.0, batch.1).await.unwrap(); } #[tokio::test] -#[ignore = "requires an authenticated historical L1 RPC fixture"] async fn test_inspect_batch_header() { use alloy_primitives::B256; use alloy_provider::ProviderBuilder; diff --git a/prover/bin/shadow-prove/src/util.rs b/prover/bin/shadow-prove/src/util.rs index 9aa8aaf64..4858f7e3b 100644 --- a/prover/bin/shadow-prove/src/util.rs +++ b/prover/bin/shadow-prove/src/util.rs @@ -50,7 +50,6 @@ pub fn read_parse_env(var_name: &'static str) -> T { } #[tokio::test] -#[ignore = "requires SHADOW_PROVING_PROVER_RPC and an external prover service"] async fn test_call_prover() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); dotenv::dotenv().ok(); diff --git a/tx-submitter/README.md b/tx-submitter/README.md index 01c4d3fe3..428197da2 100644 --- a/tx-submitter/README.md +++ b/tx-submitter/README.md @@ -11,5 +11,6 @@ ```bash cast call $ROLLUP_ADDR "lastFinalizedBatchIndex()" -r $L1RPC cast call $ROLLUP_ADDR "lastCommittedBatchIndex()" -r $L1RPC -cast call $SUBMITTER_ADDR "isActive(address)(bool)" $TX_SUBMITTER_ADDR -r $L1RPC -``` +cast call $L2_SEQUENCER_ADDR "getSequencerSet2()(address[])" -r $L2RPC +cast call $L1_STAKING_ADDR "getActiveStakers()(address[])" -r $L1RPC +``` \ No newline at end of file diff --git a/tx-submitter/constants/methods.go b/tx-submitter/constants/methods.go index 629f87f44..7de9eb498 100644 --- a/tx-submitter/constants/methods.go +++ b/tx-submitter/constants/methods.go @@ -3,10 +3,13 @@ package constants const ( // MethodCommitBatch is the method name for committing a batch (with blob when applicable) MethodCommitBatch = "commitBatch" + // MethodCommitState is the method name for recommitting batch state using stored blob hash (no blob in tx) + MethodCommitState = "commitState" // MethodFinalizeBatch is the method name for finalizing a batch MethodFinalizeBatch = "finalizeBatch" ) -func IsOwnedCommitMethod(method string) bool { - return method == MethodCommitBatch +// IsCommitLikeMethod returns true for commitBatch or commitState (same calldata shape for batch index parsing). +func IsCommitLikeMethod(method string) bool { + return method == MethodCommitBatch || method == MethodCommitState } diff --git a/tx-submitter/entry.go b/tx-submitter/entry.go index d223b3ce8..b67cf0da9 100644 --- a/tx-submitter/entry.go +++ b/tx-submitter/entry.go @@ -6,6 +6,7 @@ import ( "crypto/rsa" "fmt" "io" + "math/big" "os" "os/signal" "strings" @@ -13,6 +14,7 @@ import ( "morph-l2/bindings/bindings" "morph-l2/tx-submitter/db" + "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/metrics" @@ -21,6 +23,7 @@ import ( "morph-l2/tx-submitter/utils" "github.com/morph-l2/externalsign" + "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" @@ -41,28 +44,18 @@ func Main() func(ctx *cli.Context) error { if err != nil { return err } - if cfg.BatchConfigPreflight { - report, err := cfg.BatchConfigReportJSON() - if err != nil { - return fmt.Errorf("encode batch config preflight: %w", err) - } - _, err = fmt.Fprintln(os.Stdout, string(report)) - return err - } // log start info log.Info("starting tx submitter", "l1_rpc", cfg.L1EthRpc, "l2_rpcs", cfg.L2EthRpcs, "rollup_addr", cfg.RollupAddress, - "submitter_addr", cfg.SubmitterAddress, - "batch_block_interval_blocks", cfg.BatchBlockInterval, - "batch_timeout_seconds", cfg.BatchTimeout, - "batch_config_hash", cfg.BatchConfig().Hash(), - "batch_config_source_block_number", cfg.BatchConfigSourceBlockNumber, - "batch_config_source_block_hash", cfg.BatchConfigSourceBlockHash, + "l2_sequencer_addr", cfg.L2SequencerAddress, + "l2_gov_addr", cfg.L2GovAddress, + "l1_staking_addr", cfg.L1StakingAddress, "fee_limit", cfg.TxFeeLimit, "finalize_enable", cfg.Finalize, + "priority_rollup_enable", cfg.PriorityRollup, "rollup_interval", cfg.RollupInterval.String(), "finalize_interval", cfg.FinalizeInterval.String(), "tx_process_interval", cfg.TxProcessInterval.String(), @@ -71,6 +64,7 @@ func Main() func(ctx *cli.Context) error { "journal_path", cfg.JournalFilePath, "gas_rough_estimate", cfg.RoughEstimateGas, "gas_limit_buffer", cfg.GasLimitBuffer, + "rotator_buffer", cfg.RotatorBuffer, "rough_estimate_gas", cfg.RoughEstimateGas, "rough_estimate_base_gas", cfg.RollupTxGasBase, "rough_estimate_per_l1_msg", cfg.RollupTxGasPerL1Msg, @@ -159,10 +153,10 @@ func Main() func(ctx *cli.Context) error { return fmt.Errorf("failed to get rollup abi: %w", err) } - // L1 submitter qualification contract. - submitter, err := bindings.NewSubmitter(common.HexToAddress(cfg.SubmitterAddress), l1Client) + // l1 staking + l1Staking, err := bindings.NewL1Staking(common.HexToAddress(cfg.L1StakingAddress), l1Client) if err != nil { - return fmt.Errorf("failed to connect to submitter contract: %w", err) + return fmt.Errorf("failed to connect to l1 staking contract") } var rsaPriv *rsa.PrivateKey @@ -184,10 +178,33 @@ func Main() func(ctx *cli.Context) error { } + l1StakingAbi, err := bindings.L1StakingMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get l1 staking abi: %w", err) + } + // new event listener + filter := ethereum.FilterQuery{ + Addresses: []common.Address{common.HexToAddress(cfg.L1StakingAddress)}, + Topics: [][]common.Hash{ + {l1StakingAbi.Events["StakersRemoved"].ID}, + }, + } + ldb, err := db.New(cfg.LeveldbPathName) if err != nil { return fmt.Errorf("failed to connect leveldb: %w", err) } + eventInfoStorage := event.NewEventInfoStorage(ldb) + err = eventInfoStorage.Load() + if err != nil { + return err + } + eventIndexer := event.NewEventIndexer(l1Client, new(big.Int).SetUint64(cfg.L1StakingDeployedBlockNumber), filter, cfg.EventIndexStep, eventInfoStorage) + // new rotator + rotator := services.NewRotator(common.HexToAddress(cfg.L2SequencerAddress), common.HexToAddress(cfg.L2GovAddress), eventIndexer) + // start rorator event indexer + rotator.StartEventIndexer() + // block monitor bm := l1checker.NewBlockMonitor(cfg.BlockNotIncreasedThreshold, l1Client) @@ -203,15 +220,17 @@ func Main() func(ctx *cli.Context) error { l1Client, l2Clients, l1Rollup, - submitter, + l1Staking, chainID, privKey, rollupAddr, rollupAbi, cfg, rsaPriv, + rotator, ldb, bm, + eventInfoStorage, l2Caller, ) diff --git a/tx-submitter/event/indexer.go b/tx-submitter/event/indexer.go new file mode 100644 index 000000000..dc517ba72 --- /dev/null +++ b/tx-submitter/event/indexer.go @@ -0,0 +1,145 @@ +package event + +import ( + "context" + "math/big" + "time" + + "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/ethclient" + "github.com/morph-l2/go-ethereum/log" +) + +type EventIndexer struct { + client *ethclient.Client + deployBlock *big.Int // Block number of contract deployment + filterQuery ethereum.FilterQuery + indexStep uint64 // index step + storage IEventStorage +} + +func NewEventIndexer(client *ethclient.Client, deployedBlock *big.Int, filter ethereum.FilterQuery, indexStep uint64, storage IEventStorage) *EventIndexer { + return &EventIndexer{ + client: client, + deployBlock: deployedBlock, + filterQuery: filter, + indexStep: indexStep, + storage: storage, + } +} + +func (l *EventIndexer) Index() { + log.Info("event indexer started") + + if l.storage.BlockProcessed() == 0 { + l.storage.SetBlockProcessed(l.deployBlock.Uint64()) + err := l.storage.Store() + if err != nil { + log.Error("failed to store initial block number", "error", err) + } + } + + // Create a ticker that triggers every minute + ticker := time.NewTicker(time.Second * 15) + defer ticker.Stop() + + for range ticker.C { + // Get the current block number + currentBlock, err := l.client.BlockNumber(context.Background()) + if err != nil { + log.Error("failed to get current block number", "error", err) + continue + } + + if currentBlock <= l.storage.BlockProcessed() { + log.Info("no new block to index", "current_block", currentBlock, "last_processed_block", l.storage.BlockProcessed()) + continue + } + + // Perform indexing operation + indexedEventInfo, err := l.index(l.client, big.NewInt(int64(l.storage.BlockProcessed())), big.NewInt(int64(currentBlock))) + if err != nil { + log.Error("indexing operation failed", "error", err) + continue + } + + if indexedEventInfo != nil { + l.storage.SetBlockProcessed(indexedEventInfo.BlockProcessed) + } else { + l.storage.SetBlockProcessed(currentBlock) + } + + // Update storage + err = l.storage.Store() + if err != nil { + log.Error("event index complete, failed to update storage", "error", err) + } else { + info := l.storage.EventInfo() + log.Info("event index complete, storage updated", "processed_block", info.BlockProcessed, "block_time", info.BlockTime) + } + } +} + +// filter logs from from_block to to_block +// if the range is too large, will divide the range +func (ei *EventIndexer) index(client *ethclient.Client, fromBlock, toBlock *big.Int) (*EventInfo, error) { + + endBlock := toBlock.Uint64() + startBlock := endBlock - ei.indexStep + lastProcessedBlock := fromBlock.Uint64() + if startBlock < lastProcessedBlock { + startBlock = lastProcessedBlock + } + logFilter := ei.GetFilter() + + // Find the last unprocessed log + for endBlock >= lastProcessedBlock && endBlock > startBlock { + logFilter.FromBlock = big.NewInt(int64(startBlock)) + logFilter.ToBlock = big.NewInt(int64(endBlock)) + historicalLogs, err := client.FilterLogs(context.Background(), logFilter) + if err != nil { + log.Error("Failed to get historical logs", + "error", err, + "start_block", startBlock, + "end_block", endBlock, + ) + continue + } else { + if len(historicalLogs) > 0 { + latestLog := historicalLogs[len(historicalLogs)-1] + var block *types.Block + for { + block, err = client.BlockByNumber(context.Background(), new(big.Int).SetUint64(latestLog.BlockNumber)) + if err != nil { + log.Error("Failed to get block", "error", err) + time.Sleep(time.Second * 5) + continue + } else { + return &EventInfo{ + BlockProcessed: toBlock.Uint64(), + BlockTime: block.Time(), + }, nil + } + } + } + log.Info("backward indexing", "block_num", startBlock, "target_num", lastProcessedBlock) + // update query range + endBlock = startBlock + if endBlock <= lastProcessedBlock+ei.indexStep { + startBlock = lastProcessedBlock + 1 + } else { + startBlock = endBlock - ei.indexStep + } + + } + } + return nil, nil +} + +func (l *EventIndexer) GetFilter() ethereum.FilterQuery { + return l.filterQuery +} +func (l *EventIndexer) GetStorage() IEventStorage { + return l.storage +} diff --git a/tx-submitter/event/storage.go b/tx-submitter/event/storage.go new file mode 100644 index 000000000..dcec97af0 --- /dev/null +++ b/tx-submitter/event/storage.go @@ -0,0 +1,109 @@ +package event + +import ( + "encoding/json" + "errors" + "fmt" + "sync" + + "morph-l2/tx-submitter/db" + "morph-l2/tx-submitter/params" +) + +type IEventStorage interface { + Store() error + Load() error + BlockProcessed() uint64 + SetBlockProcessed(blockNum uint64) + BlockTime() uint64 + SetBlockTime(blockTime uint64) + EventInfo() EventInfo +} + +type EventInfo struct { + BlockTime uint64 `json:"block_time"` // event emit time + BlockProcessed uint64 `json:"block_processed"` // block processed +} + +type EventInfoStorage struct { + eventInfo EventInfo + db db.Database + mu sync.RWMutex +} + +func NewEventInfoStorage(db db.Database) *EventInfoStorage { + return &EventInfoStorage{ + db: db, + } +} + +func (e *EventInfoStorage) Store() error { + // Convert struct to JSON string + jsonData, err := json.Marshal(e.eventInfo) + if err != nil { + return fmt.Errorf("failed to convert struct to JSON: %w", err) + } + + e.mu.Lock() + defer e.mu.Unlock() + // Write JSON data to file + err = e.db.PutString(params.EventInfoKey, string(jsonData)) + if err != nil { + return fmt.Errorf("failed to write to db: err=%w, data=%v", err, jsonData) + } + return nil +} + +func (e *EventInfoStorage) Load() error { + e.mu.Lock() + defer e.mu.Unlock() + + jsonStr, err := e.db.GetString(params.EventInfoKey) + if err != nil { + if errors.Is(err, db.ErrKeyNotFound) { + // Initialize with default values if not found + e.eventInfo = EventInfo{} + return nil + } + return fmt.Errorf("failed to read from db: %w", err) + } + + err = json.Unmarshal([]byte(jsonStr), &e.eventInfo) + if err != nil { + return fmt.Errorf("failed to parse JSON: %w", err) + } + + return nil +} + +func (e *EventInfoStorage) BlockProcessed() uint64 { + e.mu.RLock() + defer e.mu.RUnlock() + return e.eventInfo.BlockProcessed +} + +func (e *EventInfoStorage) SetBlockProcessed(blockNum uint64) { + e.mu.Lock() + defer e.mu.Unlock() + e.eventInfo.BlockProcessed = blockNum +} + +func (e *EventInfoStorage) BlockTime() uint64 { + e.mu.RLock() + defer e.mu.RUnlock() + return e.eventInfo.BlockTime +} + +func (e *EventInfoStorage) SetBlockTime(blockTime uint64) { + e.mu.Lock() + defer e.mu.Unlock() + e.eventInfo.BlockTime = blockTime +} + +// EventInfo returns a copy of the current event info. +// This ensures thread safety without exposing the internal state. +func (e *EventInfoStorage) EventInfo() EventInfo { + e.mu.RLock() + defer e.mu.RUnlock() + return e.eventInfo +} diff --git a/tx-submitter/event/storage_test.go b/tx-submitter/event/storage_test.go new file mode 100644 index 000000000..2299bab52 --- /dev/null +++ b/tx-submitter/event/storage_test.go @@ -0,0 +1,40 @@ +package event + +import ( + "morph-l2/tx-submitter/db" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestEventInfoStorage(t *testing.T) { + // Create a unique test directory + testDir := filepath.Join(t.TempDir(), "testleveldb") + + // Cleanup before test (in case it exists) + os.RemoveAll(testDir) + + // Cleanup after test + t.Cleanup(func() { + os.RemoveAll(testDir) + }) + + db, err := db.New(testDir) + require.NoError(t, err) + storage := NewEventInfoStorage(db) + err = storage.Load() + require.NoError(t, err) + + storage.SetBlockTime(100) + storage.SetBlockProcessed(100) + err = storage.Store() + require.NoError(t, err) + + storage2 := NewEventInfoStorage(db) + err = storage2.Load() + require.NoError(t, err) + require.Equal(t, storage.BlockTime(), storage2.BlockTime()) + require.Equal(t, storage.BlockProcessed(), storage2.BlockProcessed()) +} diff --git a/tx-submitter/flags/flags.go b/tx-submitter/flags/flags.go index 568fe1637..cdbf1405d 100644 --- a/tx-submitter/flags/flags.go +++ b/tx-submitter/flags/flags.go @@ -3,6 +3,8 @@ package flags import ( "time" + "morph-l2/bindings/predeploys" + "github.com/urfave/cli" ) @@ -57,11 +59,11 @@ var ( Required: true, EnvVar: prefixEnvVar("ROLLUP_ADDRESS"), } - SubmitterAddressFlag = cli.StringFlag{ - Name: "submitter_address", - Usage: "Address of the Submitter qualification and stake contract", + L1StakingAddressFlag = cli.StringFlag{ + Name: "l1_staking_address", + Usage: "Address of the staking contract", Required: true, - EnvVar: prefixEnvVar("SUBMITTER_ADDRESS"), + EnvVar: prefixEnvVar("L1_STAKING_ADDRESS"), } // finalize flags @@ -72,17 +74,28 @@ var ( Required: true, } - BatchBlockIntervalFlag = cli.Uint64Flag{ - Name: "batch_block_interval", - Usage: "Static batch sealing interval in L2 blocks (may be zero if timeout is non-zero)", - EnvVar: prefixEnvVar("BATCH_BLOCK_INTERVAL"), + // decentralize config + PriorityRollupFlag = cli.BoolFlag{ + Name: "priority_rollup", + Usage: "Enable priority rollup", + EnvVar: prefixEnvVar("PRIORITY_ROLLUP"), Required: true, } - BatchTimeoutFlag = cli.Uint64Flag{ - Name: "batch_timeout", - Usage: "Static batch sealing timeout in seconds (may be zero if interval is non-zero)", - EnvVar: prefixEnvVar("BATCH_TIMEOUT"), - Required: true, + + // L2 contract + L2SequencerAddressFlag = cli.StringFlag{ + Name: "l2_sequencer_address", + Usage: "Address of the sequencer contract", + Required: false, + EnvVar: prefixEnvVar("L2_SEQUENCER_ADDRESS"), + Value: predeploys.Sequencer, + } + L2GovAddressFlag = cli.StringFlag{ + Name: "l2_gov_address", + Usage: "Address of the gov contract", + Required: false, + EnvVar: prefixEnvVar("L2_GOV_ADDRESS"), + Value: predeploys.Gov, } /* Optional Flags */ @@ -193,20 +206,12 @@ var ( EnvVar: prefixEnvVar("JOURNAL_FILE_PATH"), Value: "journal.rlp", } - BatchConfigPreflightFlag = cli.BoolFlag{ - Name: "batch_config_preflight", - Usage: "Print the effective static batch configuration and hash, then exit", - EnvVar: prefixEnvVar("BATCH_CONFIG_PREFLIGHT"), - } - BatchConfigSourceBlockNumberFlag = cli.Uint64Flag{ - Name: "batch_config_source_block_number", - Usage: "L2 block number at which the static batch values were snapshotted", - EnvVar: prefixEnvVar("BATCH_CONFIG_SOURCE_BLOCK_NUMBER"), - } - BatchConfigSourceBlockHashFlag = cli.StringFlag{ - Name: "batch_config_source_block_hash", - Usage: "L2 block hash at which the static batch values were snapshotted", - EnvVar: prefixEnvVar("BATCH_CONFIG_SOURCE_BLOCK_HASH"), + // listener processed block record path + StakingEventStoreFileFlag = cli.StringFlag{ + Name: "staking_event_store_filename", + Usage: "The file name of the storage", + EnvVar: prefixEnvVar("STAKING_EVENT_STORE_FILENAME"), + Value: "StakingEventStore.json", } TipFeeBumpFlag = cli.Uint64Flag{ @@ -283,6 +288,28 @@ var ( EnvVar: prefixEnvVar("ROUGH_ESTIMATE_GAS"), } + RotatorBufferFlag = cli.Int64Flag{ + Name: "rotator_buffer", + Usage: "rotation interval buffer", + Value: 15, + EnvVar: prefixEnvVar("ROTATOR_BUFFER"), + } + + // l1 staking deployed blocknum + L1StakingDeployedBlocknumFlag = cli.Uint64Flag{ + Name: "l1_staking_deployed_blocknum", + Usage: "The deployed block number of L1Staking", + EnvVar: prefixEnvVar("L1_STAKING_DEPLOYED_BLOCKNUM"), + Required: true, + } + + // event indexer + EventIndexStepFlag = cli.Uint64Flag{ + Name: "event_index_step", + Usage: "The step size for event indexing", + Value: 100, + EnvVar: prefixEnvVar("EVENT_INDEX_STEP"), + } LeveldbPathNameFlag = cli.StringFlag{ Name: "leveldb_path_name", Usage: "The path name of the leveldb", @@ -329,10 +356,10 @@ var requiredFlags = []cli.Flag{ RollupAddressFlag, TxTimeoutFlag, FinalizeFlag, + PriorityRollupFlag, TxFeeLimitFlag, - SubmitterAddressFlag, - BatchBlockIntervalFlag, - BatchTimeoutFlag, + L1StakingAddressFlag, + L1StakingDeployedBlocknumFlag, } var optionalFlags = []cli.Flag{ @@ -355,11 +382,10 @@ var optionalFlags = []cli.Flag{ GasLimitBuffer, JournalFlag, - BatchConfigPreflightFlag, - BatchConfigSourceBlockNumberFlag, - BatchConfigSourceBlockHashFlag, PrivateKeyFlag, + L2SequencerAddressFlag, + L2GovAddressFlag, TipFeeBumpFlag, MaxTipFlag, MinTipFlag, @@ -374,6 +400,9 @@ var optionalFlags = []cli.Flag{ ExternalSignUrl, ExternalSignRsaPriv, RoughEstimateGasFlag, + RotatorBufferFlag, + StakingEventStoreFileFlag, + EventIndexStepFlag, LeveldbPathNameFlag, BlockNotIncreasedThreshold, diff --git a/tx-submitter/iface/client.go b/tx-submitter/iface/client.go index 228dd1e4e..2081355db 100644 --- a/tx-submitter/iface/client.go +++ b/tx-submitter/iface/client.go @@ -254,14 +254,14 @@ func (c *L2Clients) GetBlockTraceByNumber(ctx context.Context, number *big.Int) func (c *L2Clients) GetRollupBatchByIndex(ctx context.Context, batchIndex uint64) (*eth.RPCRollupBatch, error) { var result *eth.RPCRollupBatch err := c.tryAllClients(func(client L2Client) error { - candidate, err := client.GetRollupBatchByIndex(ctx, batchIndex) + var err error + result, err = client.GetRollupBatchByIndex(ctx, batchIndex) if err != nil { return err } - if candidate == nil { - return errors.New("rollup batch not found") + if result != nil && len(result.Signatures) > 0 { + return nil } - result = candidate return nil }) diff --git a/tx-submitter/iface/rollup.go b/tx-submitter/iface/rollup.go index 6ee543c6b..9a60a64b5 100644 --- a/tx-submitter/iface/rollup.go +++ b/tx-submitter/iface/rollup.go @@ -11,32 +11,41 @@ import ( ) type IRollup interface { - BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) - CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput) (*types.Transaction, error) + CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) - FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) - MessageQueue(opts *bind.CallOpts) (common.Address, error) FinalizeBatch(*bind.TransactOpts, []byte) (*types.Transaction, error) BatchInsideChallengeWindow(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) BatchExist(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) + BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) FilterCommitBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupCommitBatchIterator, error) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) - FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) } -// ISubmitter is the minimum qualification surface required by the official -// submitter. Selection/rotation is deliberately not part of this interface. -type ISubmitter interface { - IsActive(opts *bind.CallOpts, addr common.Address) (bool, error) +// IL2Sequencer is the interface for the sequencer on L2 +type IL2Sequencer interface { + SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) +} + +type IL2Gov interface { + RollupEpoch(opts *bind.CallOpts) (*big.Int, error) + BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) + BatchTimeout(opts *bind.CallOpts) (*big.Int, error) +} + +type IL1Staking interface { + IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) + GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) + GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) + GetStakers(opts *bind.CallOpts) ([255]common.Address, error) } type IL2MessagePasser interface { diff --git a/tx-submitter/mock/event_storage.go b/tx-submitter/mock/event_storage.go new file mode 100644 index 000000000..e26087720 --- /dev/null +++ b/tx-submitter/mock/event_storage.go @@ -0,0 +1,26 @@ +package mock + +import ( + "morph-l2/tx-submitter/event" +) + +// MockEventInfoStorage is a mock implementation of the EventInfoStorage +type MockEventInfoStorage struct { + event.EventInfoStorage +} + +// NewMockEventInfoStorage creates a new mock EventInfoStorage +func NewMockEventInfoStorage() *event.EventInfoStorage { + mockDB := NewMockDB() + return event.NewEventInfoStorage(mockDB) +} + +// Store implements the Store method +func (m *MockEventInfoStorage) Store() error { + return nil +} + +// Load implements the Load method +func (m *MockEventInfoStorage) Load() error { + return nil +} diff --git a/tx-submitter/mock/l1staking.go b/tx-submitter/mock/l1staking.go new file mode 100644 index 000000000..08939b834 --- /dev/null +++ b/tx-submitter/mock/l1staking.go @@ -0,0 +1,62 @@ +package mock + +import ( + "math/big" + + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" +) + +// MockL1Staking is a mock implementation of IL1Staking +type MockL1Staking struct { + activeStakers []common.Address +} + +// NewMockL1Staking creates a new mock L1Staking instance +func NewMockL1Staking() *MockL1Staking { + return &MockL1Staking{ + activeStakers: []common.Address{}, + } +} + +// IsStaker implements IL1Staking +func (m *MockL1Staking) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { + for _, staker := range m.activeStakers { + if staker == addr { + return true, nil + } + } + return false, nil +} + +// GetStakersBitmap implements IL1Staking +func (m *MockL1Staking) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { + bitmap := big.NewInt(0) + for i, staker := range _stakers { + for _, activeStaker := range m.activeStakers { + if staker == activeStaker { + bitmap.SetBit(bitmap, i, 1) + } + } + } + return bitmap, nil +} + +// GetActiveStakers implements IL1Staking +func (m *MockL1Staking) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { + return m.activeStakers, nil +} + +// GetStakers implements IL1Staking +func (m *MockL1Staking) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { + var result [255]common.Address + for i := 0; i < len(m.activeStakers) && i < 255; i++ { + result[i] = m.activeStakers[i] + } + return result, nil +} + +// SetActiveStakers sets the active stakers for testing +func (m *MockL1Staking) SetActiveStakers(stakers []common.Address) { + m.activeStakers = stakers +} diff --git a/tx-submitter/mock/l2client.go b/tx-submitter/mock/l2client.go index c73e1c816..d1acf1b8a 100644 --- a/tx-submitter/mock/l2client.go +++ b/tx-submitter/mock/l2client.go @@ -3,6 +3,7 @@ package mock import ( "context" "math/big" + "time" "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" @@ -20,16 +21,27 @@ type L2ClientWrapper struct { TipCap *big.Int reorgDepth int64 reorgCount int64 + sequencerSet []common.Address BaseFee *big.Int } func NewL2ClientWrapper() *L2ClientWrapper { + // Create mock CallContractResult for epoch update time + // Return a timestamp from 1 hour ago + timestamp := time.Now().Add(-1 * time.Hour).Unix() result := make([]byte, 32) + big.NewInt(timestamp).FillBytes(result) + + // Create a mock sequencer set with two addresses + mockAddr1 := common.HexToAddress("0x1111111111111111111111111111111111111111") + mockAddr2 := common.HexToAddress("0x2222222222222222222222222222222222222222") + sequencerSet := []common.Address{mockAddr1, mockAddr2} return &L2ClientWrapper{ TipCap: big.NewInt(1e9), Balance: big.NewInt(1e18), CallContractResult: result, + sequencerSet: sequencerSet, BaseFee: big.NewInt(1e9), } } @@ -40,6 +52,31 @@ func (l *L2ClientWrapper) CallContract(ctx context.Context, msg ethereum.CallMsg return nil, l.CallContractErr } + // If calling the sequencer set method, return the mock sequencer set + if len(msg.Data) >= 4 { + methodID := msg.Data[:4] + // Method ID for GetSequencerSet2() + if string(methodID) == "\x77\xd7\xdf\xfb" { + // Encode the sequencer set into bytes + result := make([]byte, 0) + // First 32 bytes for offset + offset := make([]byte, 32) + big.NewInt(32).FillBytes(offset) + result = append(result, offset...) + // Next 32 bytes for length + length := make([]byte, 32) + big.NewInt(int64(len(l.sequencerSet))).FillBytes(length) + result = append(result, length...) + // Then the addresses + for _, addr := range l.sequencerSet { + addrBytes := make([]byte, 32) + copy(addrBytes[12:], addr.Bytes()) + result = append(result, addrBytes...) + } + return result, nil + } + } + return l.CallContractResult, nil } @@ -170,3 +207,8 @@ func (l *L2ClientWrapper) SuggestGasTipCap(ctx context.Context) (*big.Int, error } return big.NewInt(1e9), nil } + +// GetSequencerSet2 implements IL2Sequencer +func (m *L2ClientWrapper) GetSequencerSet2() ([]common.Address, error) { + return m.sequencerSet, nil +} diff --git a/tx-submitter/mock/rollup.go b/tx-submitter/mock/rollup.go index 6542fc38e..cf889c6a4 100644 --- a/tx-submitter/mock/rollup.go +++ b/tx-submitter/mock/rollup.go @@ -7,7 +7,6 @@ import ( "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" "morph-l2/bindings/bindings" ) @@ -22,16 +21,6 @@ type MockRollup struct { finalizeTx *types.Transaction } -// BatchBlobVersionedHashes implements IRollup. -func (m *MockRollup) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { - return [32]byte{}, nil -} - -// MessageQueue implements IRollup. -func (m *MockRollup) MessageQueue(opts *bind.CallOpts) (common.Address, error) { - return common.Address{}, nil -} - // NewMockRollup creates a new instance of MockRollup func NewMockRollup() *MockRollup { return &MockRollup{ @@ -48,14 +37,10 @@ func (m *MockRollup) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, err } // CommitBatch implements IRollup -func (m *MockRollup) CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput) (*types.Transaction, error) { +func (m *MockRollup) CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) { return m.batchTx, nil } -func (m *MockRollup) FinalizedStateRoots(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { - return [32]byte{}, nil -} - // LastFinalizedBatchIndex implements IRollup func (m *MockRollup) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) { return m.lastFinalizedBatchIndex, nil @@ -81,22 +66,28 @@ func (m *MockRollup) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) return [32]byte{}, nil } +// BatchBlobVersionedHashes implements IRollup (no stored hash by default) +func (m *MockRollup) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { + return [32]byte{}, nil +} + // BatchDataStore implements IRollup func (m *MockRollup) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }, error) { return struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - Submitter common.Address + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + SignedSequencersBitmap *big.Int }{ - OriginTimestamp: big.NewInt(0), - FinalizeTimestamp: big.NewInt(0), - BlockNumber: big.NewInt(0), + OriginTimestamp: big.NewInt(0), + FinalizeTimestamp: big.NewInt(0), + BlockNumber: big.NewInt(0), + SignedSequencersBitmap: big.NewInt(0), }, nil } @@ -110,11 +101,6 @@ func (m *MockRollup) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*bi return nil, nil } -// FilterRevertBatch implements IRollup. -func (m *MockRollup) FilterRevertBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupRevertBatchIterator, error) { - return nil, errors.New("FilterRevertBatch not implemented in mock") -} - // SetLastCommittedBatchIndex sets the mock value for LastCommittedBatchIndex func (m *MockRollup) SetLastCommittedBatchIndex(index *big.Int) { m.lastCommittedBatchIndex = index diff --git a/tx-submitter/mock/submitter.go b/tx-submitter/mock/submitter.go deleted file mode 100644 index 03a760318..000000000 --- a/tx-submitter/mock/submitter.go +++ /dev/null @@ -1,63 +0,0 @@ -package mock - -import ( - "sync" - - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" -) - -// MockSubmitter implements the minimal submitter qualification view used by -// the transaction submitter. -type MockSubmitter struct { - mu sync.RWMutex - active map[common.Address]bool - defaultOn bool - lastQuery common.Address - err error -} - -func NewMockSubmitter() *MockSubmitter { - return &MockSubmitter{ - active: make(map[common.Address]bool), - defaultOn: true, - } -} - -func (m *MockSubmitter) IsActive(_ *bind.CallOpts, addr common.Address) (bool, error) { - m.mu.Lock() - defer m.mu.Unlock() - m.lastQuery = addr - if m.err != nil { - return false, m.err - } - active, configured := m.active[addr] - if !configured { - return m.defaultOn, nil - } - return active, nil -} - -func (m *MockSubmitter) SetActive(addr common.Address, active bool) { - m.mu.Lock() - defer m.mu.Unlock() - m.active[addr] = active -} - -func (m *MockSubmitter) SetDefaultActive(active bool) { - m.mu.Lock() - defer m.mu.Unlock() - m.defaultOn = active -} - -func (m *MockSubmitter) SetError(err error) { - m.mu.Lock() - defer m.mu.Unlock() - m.err = err -} - -func (m *MockSubmitter) LastQuery() common.Address { - m.mu.RLock() - defer m.mu.RUnlock() - return m.lastQuery -} diff --git a/tx-submitter/params/leveldb_keys.go b/tx-submitter/params/leveldb_keys.go new file mode 100644 index 000000000..b998e6de9 --- /dev/null +++ b/tx-submitter/params/leveldb_keys.go @@ -0,0 +1,5 @@ +package params + +const ( + EventInfoKey = "event_info" +) diff --git a/tx-submitter/services/batch_fecher.go b/tx-submitter/services/batch_fecher.go index f87b11fdc..7c658ab81 100644 --- a/tx-submitter/services/batch_fecher.go +++ b/tx-submitter/services/batch_fecher.go @@ -27,7 +27,8 @@ func (bf *BatchFetcher) GetRollupBatchByIndex(index uint64) (*eth.RPCRollupBatch lastErr = err continue } - if batch != nil { + // Validate that batch exists and has signatures before returning + if batch != nil && len(batch.Signatures) > 0 { return batch, nil } } diff --git a/tx-submitter/services/pendingtx.go b/tx-submitter/services/pendingtx.go index 02632003a..b94735b94 100644 --- a/tx-submitter/services/pendingtx.go +++ b/tx-submitter/services/pendingtx.go @@ -1,7 +1,6 @@ package services import ( - "bytes" "fmt" "sort" "sync" @@ -41,7 +40,7 @@ type PendingTxs struct { } // NewPendingTxs creates a new PendingTxs instance. -// Only current commitBatch transactions are owned by this process. +// Commit-like txs (commitBatch / commitState) are detected via utils.ParseMethod + constants.IsCommitLikeMethod, not stored method IDs. func NewPendingTxs(journal Journal) *PendingTxs { return &PendingTxs{ txinfos: make(map[common.Hash]*types.TxRecord), @@ -222,11 +221,8 @@ func (pt *PendingTxs) ExistedIndex(index uint64) bool { for i := len(txs) - 1; i >= 0; i-- { tx := txs[i].Tx - if constants.IsOwnedCommitMethod(utils.ParseMethod(tx, abi)) { - pindex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), abi) - if err != nil { - continue - } + if constants.IsCommitLikeMethod(utils.ParseMethod(tx, abi)) { + pindex := utils.ParseParentBatchIndex(tx.Data()) + 1 if index == pindex { return true } @@ -246,40 +242,20 @@ func (pt *PendingTxs) Recover(txs []*ethtypes.Transaction, abi *abi.ABI) error { var maxCommitBatchIndex, maxFinalizeBatchIndex uint64 for _, tx := range txs { - method := "cancel" + // Get method name + method := utils.ParseMethod(tx, abi) + + // Get batch index based on method var batchIndex uint64 - var err error - finalizeMethod, hasFinalizeMethod := abi.Methods[constants.MethodFinalizeBatch] - if len(tx.Data()) != 0 { - ownedMethod, _, ownedErr := utils.ParseOwnedCommit(tx.Data(), abi) - switch { - case ownedErr == nil: - method = ownedMethod - if tx.Type() != ethtypes.BlobTxType || tx.BlobTxSidecar() == nil || len(tx.BlobTxSidecar().Blobs) == 0 || len(tx.BlobHashes()) == 0 { - return fmt.Errorf("owned commit journal entry %s is missing its blob sidecar; use a fresh data directory", tx.Hash()) - } - batchIndex, err = utils.ParseOwnedCommitBatchIndex(tx.Data(), abi) - if err != nil { - return fmt.Errorf("invalid owned commit journal entry %s: %w", tx.Hash(), err) - } - if batchIndex > maxCommitBatchIndex { - maxCommitBatchIndex = batchIndex - } - case hasFinalizeMethod && len(tx.Data()) >= 4 && bytes.Equal(tx.Data()[:4], finalizeMethod.ID): - method = constants.MethodFinalizeBatch - if _, err := finalizeMethod.Inputs.Unpack(tx.Data()[4:]); err != nil { - return fmt.Errorf("invalid finalize journal entry %s: %w", tx.Hash(), err) - } - batchIndex = utils.ParseFBatchIndex(tx.Data()) - if batchIndex > maxFinalizeBatchIndex { - maxFinalizeBatchIndex = batchIndex - } - default: - selector := tx.Data() - if len(selector) > 4 { - selector = selector[:4] - } - return fmt.Errorf("unsupported legacy or unknown journal calldata in tx %s (selector 0x%x); use a fresh data directory", tx.Hash(), selector) + if constants.IsCommitLikeMethod(method) { + batchIndex = utils.ParseParentBatchIndex(tx.Data()) + 1 + if batchIndex > maxCommitBatchIndex { + maxCommitBatchIndex = batchIndex + } + } else if method == constants.MethodFinalizeBatch { + batchIndex = utils.ParseFBatchIndex(tx.Data()) + if batchIndex > maxFinalizeBatchIndex { + maxFinalizeBatchIndex = batchIndex } } diff --git a/tx-submitter/services/pendingtx_test.go b/tx-submitter/services/pendingtx_test.go deleted file mode 100644 index 370f1a0ad..000000000 --- a/tx-submitter/services/pendingtx_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package services - -import ( - "encoding/binary" - "encoding/hex" - "math/big" - "testing" - - "github.com/holiman/uint256" - "github.com/morph-l2/go-ethereum/common" - ethtypes "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/crypto/kzg4844" - "github.com/stretchr/testify/require" - - "morph-l2/bindings/bindings" - "morph-l2/tx-submitter/mock" -) - -func TestPendingTxsRecoverRejectsNonOwnedCalldata(t *testing.T) { - current, err := bindings.RollupMetaData.GetAbi() - require.NoError(t, err) - - selectors := map[string]string{ - "pre submitter commitBatch": "428868b5", - "pre submitter commitState": "1e8825be", - "pre submitter commitBatchWithProof": "4e8f1d67", - "unknown": "deadbeef", - } - selectors["current commitState"] = hex.EncodeToString(current.Methods["commitState"].ID) - selectors["current commitBatchWithProof"] = hex.EncodeToString(current.Methods["commitBatchWithProof"].ID) - - for name, selector := range selectors { - t.Run(name, func(t *testing.T) { - data, err := hex.DecodeString(selector) - require.NoError(t, err) - tx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ - ChainID: big.NewInt(1), - To: &common.Address{}, - Data: data, - }) - pending := NewPendingTxs(mock.NewMockJournal()) - err = pending.Recover([]*ethtypes.Transaction{tx}, current) - require.ErrorContains(t, err, "legacy or unknown journal calldata") - require.Zero(t, pending.Len()) - }) - } -} - -func TestPendingTxsRecoverAcceptsCurrentFreshBlobCommit(t *testing.T) { - current, err := bindings.RollupMetaData.GetAbi() - require.NoError(t, err) - require.Equal(t, "41f756da", hex.EncodeToString(current.Methods["commitBatch"].ID)) - - parentHeader := make([]byte, 9) - binary.BigEndian.PutUint64(parentHeader[1:], 7) - calldata, err := current.Pack("commitBatch", bindings.IRollupBatchDataInput{ - ParentBatchHeader: parentHeader, - }) - require.NoError(t, err) - - tx := ethtypes.NewTx(ðtypes.BlobTx{ - ChainID: uint256.NewInt(1), - To: common.Address{}, - Data: calldata, - BlobFeeCap: uint256.NewInt(1), - BlobHashes: []common.Hash{{1}}, - Sidecar: ðtypes.BlobTxSidecar{ - Blobs: []kzg4844.Blob{{1}}, - Commitments: []kzg4844.Commitment{{1}}, - }, - }) - pending := NewPendingTxs(mock.NewMockJournal()) - require.NoError(t, pending.Recover([]*ethtypes.Transaction{tx}, current)) - require.Equal(t, 1, pending.Len()) - require.Equal(t, uint64(8), pending.GetPindex()) -} diff --git a/tx-submitter/services/rollup.go b/tx-submitter/services/rollup.go index 34a9a9c66..2df98cffd 100644 --- a/tx-submitter/services/rollup.go +++ b/tx-submitter/services/rollup.go @@ -30,6 +30,7 @@ import ( "morph-l2/common/blob" "morph-l2/tx-submitter/constants" "morph-l2/tx-submitter/db" + "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/localpool" @@ -41,23 +42,26 @@ import ( const ( txSlotSize = 32 * 1024 txMaxSize = 4 * txSlotSize // 128KB + rotatorWait = 3 * time.Second rollupSumKey = "rollup_sum" finalizeSumKey = "finalize_sum" collectedL1FeeSumKey = "collected_l1_fee_sum" ) type Rollup struct { - ctx context.Context - metrics *metrics.Metrics - l1RpcClient *rpc.Client - L1Client iface.Client - L2Clients []iface.L2Client - Rollup iface.IRollup - Submitter iface.ISubmitter - chainId *big.Int - privKey *ecdsa.PrivateKey - rollupAddr common.Address - abi *abi.ABI + ctx context.Context + metrics *metrics.Metrics + l1RpcClient *rpc.Client + L1Client iface.Client + L2Clients []iface.L2Client + Rollup iface.IRollup + Staking iface.IL1Staking + chainId *big.Int + privKey *ecdsa.PrivateKey + rollupAddr common.Address + abi *abi.ABI + // rotator + rotator *Rotator pendingTxs *PendingTxs rollupFinalizeMu sync.Mutex externalRsaPriv *rsa.PrivateKey @@ -77,6 +81,7 @@ type Rollup struct { batchCache *batch.BatchCache batchCacheLegacy *types.BatchCacheLegacy bm *l1checker.BlockMonitor + eventInfoStorage *event.EventInfoStorage reorgDetector iface.IReorgDetector ChainConfigMap blob.ChainBlobConfigs @@ -89,15 +94,17 @@ func NewRollup( l1 iface.Client, l2Clients []iface.L2Client, rollup iface.IRollup, - submitter iface.ISubmitter, + staking iface.IL1Staking, chainId *big.Int, priKey *ecdsa.PrivateKey, rollupAddr common.Address, abi *abi.ABI, cfg utils.Config, rsaPriv *rsa.PrivateKey, + rotator *Rotator, ldb *db.Db, bm *l1checker.BlockMonitor, + eventInfoStorage *event.EventInfoStorage, l2Caller *types.L2Caller, ) *Rollup { reorgDetector := NewReorgDetector(l1) @@ -107,12 +114,13 @@ func NewRollup( l1RpcClient: l1RpcClient, L1Client: l1, Rollup: rollup, - Submitter: submitter, + Staking: staking, L2Clients: l2Clients, privKey: priKey, chainId: chainId, rollupAddr: rollupAddr, abi: abi, + rotator: rotator, cfg: cfg, signer: ethtypes.LatestSignerForChainID(chainId), externalRsaPriv: rsaPriv, @@ -122,17 +130,17 @@ func NewRollup( return cfg.BatchV2UpgradeTime > 0 && blockTimestamp >= cfg.BatchV2UpgradeTime }, cfg.MaxBlobCount, - cfg.BatchConfig(), l1, &iface.L2Clients{Clients: l2Clients}, rollup, l2Caller, ldb, ), - ldb: ldb, - bm: bm, - reorgDetector: reorgDetector, - ChainConfigMap: blob.ChainConfigMap, + ldb: ldb, + bm: bm, + eventInfoStorage: eventInfoStorage, + reorgDetector: reorgDetector, + ChainConfigMap: blob.ChainConfigMap, } if !cfg.SealBatch { fetcher := NewBatchFetcher(l2Clients) @@ -148,38 +156,26 @@ func (r *Rollup) Start() error { return err } - // Cold start is synchronous and fail-closed. On an empty database this - // reconstructs the finalized anchor and committed range from canonical L1, - // then packs every L2 block through the observed head before any journal or - // submission loop is created. - if r.cfg.SealBatch { - if err := r.batchCache.InitAndSyncFromDatabase(); err != nil { - return r.rollbackCanonicalBootstrap("initialize batch cache from canonical state", err) - } - if err := r.batchCache.AssembleCurrentBatchHeader(); err != nil { - return r.rollbackCanonicalBootstrap("assemble downtime L2 blocks", err) - } - } - // journal jn := localpool.New(r.cfg.JournalFilePath) - if err := jn.Init(); err != nil { - return r.failStartup("journal file init failed", err) + err := jn.Init() + if err != nil { + log.Crit("journal file init failed", "err", err) } // pendingtxs r.pendingTxs = NewPendingTxs(jn) txs, err := jn.ParseAllTxs() if err != nil { - return r.failStartup("parse pending transaction journal", err) + log.Crit("parse l1 mempool error", "error", err) } if err := r.pendingTxs.Recover(txs, r.abi); err != nil { - return r.failStartup("recover pending transactions", err) + log.Crit("failed to recover pending transactions", "error", err) } // init fee metrics sum err = r.InitFeeMetricsSum() if err != nil { - return r.failStartup("init fee metrics sum failed", err) + return fmt.Errorf("init fee metrics sum failed: %w", err) } /// start services @@ -278,6 +274,21 @@ func (r *Rollup) Start() error { if r.cfg.SealBatch { var batchCacheSyncMu sync.Mutex + + go func() { + batchCacheSyncMu.Lock() + defer batchCacheSyncMu.Unlock() + for { + + if err = r.batchCache.InitAndSyncFromDatabase(); err != nil { + log.Error("init and sync from database failed, wait for the next try", "error", err) + time.Sleep(5 * time.Second) + continue + } + break + } + }() + go utils.Loop(r.ctx, r.cfg.TxProcessInterval, func() { batchCacheSyncMu.Lock() defer batchCacheSyncMu.Unlock() @@ -297,20 +308,6 @@ func (r *Rollup) Start() error { return nil } -func (r *Rollup) rollbackCanonicalBootstrap(stage string, cause error) error { - if resetErr := r.batchCache.ResetCanonicalBootstrap(); resetErr != nil { - return fmt.Errorf("%s: %v; rollback canonical bootstrap: %w", stage, cause, resetErr) - } - return fmt.Errorf("%s: %w", stage, cause) -} - -func (r *Rollup) failStartup(stage string, cause error) error { - if r.cfg.SealBatch { - return r.rollbackCanonicalBootstrap(stage, cause) - } - return fmt.Errorf("%s: %w", stage, cause) -} - func (r *Rollup) ProcessTx() error { // Check for reorgs first with exponential backoff retry hasReorg, depth, err := r.detectReorgWithRetry() @@ -329,6 +326,45 @@ func (r *Rollup) ProcessTx() error { return nil } + // Check if this submitter should process transactions + if err = r.checkSubmitterTurn(); err != nil { + if errors.Is(err, errNotMyTurn) { + // If rotator is not configured or not yet initialized, just skip this round safely. + if r.rotator == nil || r.rotator.startTime == nil || r.rotator.epoch == nil { + log.Info("Awaiting turn for transaction processing, but rotator state is not initialized", + "has_rotator", r.rotator != nil) + return nil + } + + // Get current submitter index for logging + activeSubmitter, activeIndex, rotErr := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) + if rotErr != nil || activeSubmitter == nil { + log.Warn("Failed to get current submitter while awaiting turn", + "error", rotErr) + return nil + } + + // Calculate rotation timing information + past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() + start := time.Now().Unix() - past + end := start + r.rotator.epoch.Int64() + timeLeft := end - time.Now().Unix() + + // Format timestamps for human readability + endTimeFormatted := utils.FormatTime(big.NewInt(end)) + timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) + + log.Info("Awaiting turn for transaction processing", + "current_submitter", activeSubmitter.Hex(), + "submitter_index", activeIndex, + "total_submitters", len(r.rotator.GetSubmitterSet()), + "next_rotation", endTimeFormatted, + "time_remaining", timeLeftFormatted) + return nil + } + return err + } + // Process each transaction for _, txRecord := range txRecords { if err := r.processSingleTx(txRecord); err != nil { @@ -356,6 +392,59 @@ func (r *Rollup) detectReorgWithRetry() (bool, uint64, error) { return false, 0, lastErr } +var errNotMyTurn = errors.New("not my turn") + +func (r *Rollup) checkSubmitterTurn() error { + // If we are in priority rollup mode or rotator is not configured, always allow processing. + if r.cfg.PriorityRollup || r.rotator == nil { + return nil + } + + activeSubmitter, submitterIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) + if err != nil { + return fmt.Errorf("rollup: get current submitter err, %w", err) + } + + myAddress := r.WalletAddr().Hex() + activeAddress := activeSubmitter.Hex() + isMyTurn := activeAddress == myAddress + + // Calculate rotation timing information + if r.rotator.startTime == nil || r.rotator.epoch == nil { + log.Warn("rotator state not initialized, skipping submitter turn check", + "has_rotator", r.rotator != nil) + return errNotMyTurn + } + past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() + start := time.Now().Unix() - past + end := start + r.rotator.epoch.Int64() + timeLeft := end - time.Now().Unix() + + // Format timestamps for human readability + startTimeFormatted := utils.FormatTime(big.NewInt(start)) + endTimeFormatted := utils.FormatTime(big.NewInt(end)) + timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) + + if !isMyTurn { + log.Debug("Not active submitter", + "active_submitter", activeAddress, + "index", submitterIndex, + "my_address", myAddress, + "total_submitters", len(r.rotator.GetSubmitterSet()), + "rotation_end", endTimeFormatted, + "time_remaining", timeLeftFormatted) + return errNotMyTurn + } + + log.Info("Active submitter status", + "index", submitterIndex, + "total_submitters", len(r.rotator.GetSubmitterSet()), + "rotation_start", startTimeFormatted, + "rotation_end", endTimeFormatted, + "time_remaining", timeLeftFormatted) + return nil +} + // Handle chain reorganization (metrics + pending pool; DetectReorg only detects and updates block history). func (r *Rollup) handleReorg(depth uint64) error { r.metrics.SetReorgDepth(float64(depth)) @@ -430,7 +519,7 @@ func (r *Rollup) updateFeeMetrics(tx *ethtypes.Transaction, receipt *ethtypes.Re txFeeFloat, _ := txFeeEth.Float64() // Update metrics based on transaction type - if constants.IsOwnedCommitMethod(method) { + if constants.IsCommitLikeMethod(method) { r.rollupFeeSum += txFeeFloat r.metrics.RollupCostSum.Add(txFeeFloat) r.metrics.RollupCost.Set(txFeeFloat) @@ -492,11 +581,8 @@ func (r *Rollup) getTxStatus(tx *ethtypes.Transaction) (*txStatus, error) { func (r *Rollup) handlePendingTx(txRecord *types.TxRecord, tx *ethtypes.Transaction, method string) error { // Obsolete / doomed txs: cancel before timeout handling so we do not resubmit a tx that will revert. - if constants.IsOwnedCommitMethod(method) { - batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) - if err != nil { - return fmt.Errorf("parse owned commit batch index: %w", err) - } + if constants.IsCommitLikeMethod(method) { + batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 lastCommitted, err := r.Rollup.LastCommittedBatchIndex(nil) if err != nil { return fmt.Errorf("get last committed batch index error: %w", err) @@ -686,11 +772,8 @@ func (r *Rollup) handleConfirmedTx(txRecord *types.TxRecord, tx *ethtypes.Transa method := utils.ParseMethod(tx, r.abi) if status.receipt.Status == ethtypes.ReceiptStatusFailed { - if constants.IsOwnedCommitMethod(method) { - batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) - if err != nil { - return fmt.Errorf("parse owned commit batch index: %w", err) - } + if constants.IsCommitLikeMethod(method) { + batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 lastCommitted, err := r.Rollup.LastCommittedBatchIndex(nil) if err != nil { return fmt.Errorf("get last committed batch index error: %w", err) @@ -719,11 +802,8 @@ func (r *Rollup) handleConfirmedTx(txRecord *types.TxRecord, tx *ethtypes.Transa } } } else { // Transaction succeeded - if constants.IsOwnedCommitMethod(method) { - batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) - if err != nil { - return fmt.Errorf("parse owned commit batch index: %w", err) - } + if constants.IsCommitLikeMethod(method) { + batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 log.Info("Successfully committed batch", "method", method, "batch_index", batchIndex, "tx_hash", tx.Hash().String(), "block_number", status.receipt.BlockNumber.Uint64(), "gas_used", status.receipt.GasUsed, "confirm", confirmations) } else if method == constants.MethodFinalizeBatch { batchIndex := utils.ParseFBatchIndex(tx.Data()) @@ -913,6 +993,84 @@ func (r *Rollup) finalize() error { } func (r *Rollup) rollup() error { + // Get current block height + if !r.cfg.PriorityRollup { + activeSubmitter, activeIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) + if err != nil { + return fmt.Errorf("rollup: get current submitter err, %w", err) + } + + err = r.eventInfoStorage.Load() + if err != nil { + return fmt.Errorf("failed to load storage in rollup: %w", err) + } + log.Debug("Indexer status", + "blocks_processed", r.eventInfoStorage.BlockProcessed(), + "last_event_time", r.eventInfoStorage.BlockTime()) + + // get current block number + blockNumber, err := r.L1Client.BlockNumber(context.Background()) + if err != nil { + return fmt.Errorf("failed to get block number in rollup: %w", err) + } + // set metrics + r.metrics.SetIndexerBlockProcessed(r.eventInfoStorage.BlockProcessed()) + // check if indexed block number is too old + if blockNumber > r.eventInfoStorage.BlockProcessed()+100 { + log.Info("Indexer sync required", + "module", r.GetModuleName(), + "current_block", blockNumber, + "processed_block", r.eventInfoStorage.BlockProcessed(), + "blocks_behind", blockNumber-r.eventInfoStorage.BlockProcessed()) + return nil + } + + past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() + start := time.Now().Unix() - past + end := start + r.rotator.epoch.Int64() + + // Calculate time remaining in current turn + timeLeft := end - time.Now().Unix() + myAddress := r.WalletAddr().Hex() + activeAddress := activeSubmitter.Hex() + isMyTurn := activeAddress == myAddress + totalSubmitters := len(r.rotator.GetSubmitterSet()) + + // Format timestamps for human readability + startTimeFormatted := utils.FormatTime(big.NewInt(start)) + endTimeFormatted := utils.FormatTime(big.NewInt(end)) + timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) + + log.Info("Rotation status", + "submitter_index", activeIndex, + "active_submitter", activeAddress, + "my_address", myAddress, + "total_submitters", totalSubmitters, + "is_my_turn", isMyTurn, + "rotation_start", startTimeFormatted, + "rotation_end", endTimeFormatted, + "time_remaining", timeLeftFormatted) + + if isMyTurn { + if timeLeft < r.cfg.RotatorBuffer { + bufferFormatted := fmt.Sprintf("%dm%ds", r.cfg.RotatorBuffer/60, r.cfg.RotatorBuffer%60) + log.Info("Insufficient time for rollup", + "time_remaining", timeLeftFormatted, + "buffer_required", bufferFormatted) + return nil + } + + log.Info("Starting rollup", + "submitter_index", activeIndex, + "total_submitters", totalSubmitters) + } else { + log.Info("Skipping rollup - not active submitter", + "active_index", activeIndex, + "active_submitter", activeAddress) + return nil + } + } + if pendingN := r.pendingTxs.Len(); pendingN > int(r.cfg.MaxTxsInPendingPool) { log.Info("Pending pool full", "current_size", pendingN, @@ -957,6 +1115,10 @@ func (r *Rollup) rollup() error { return nil } + signature, err := r.buildSignatureInput(rpcRollupBatch) + if err != nil { + return err + } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -967,15 +1129,33 @@ func (r *Rollup) rollup() error { WithdrawalRoot: rpcRollupBatch.WithdrawRoot, } + storedBlobHash, err := r.Rollup.BatchBlobVersionedHashes(nil, big.NewInt(int64(batchIndex))) + if err != nil { + return fmt.Errorf("get batch blob versioned hash: %w", err) + } + useCommitState := storedBlobHash != [32]byte{} + if useCommitState { + if err := r.validateStoredBlobAgainstSealedHeader(storedBlobHash, batchIndex); err != nil { + return err + } + log.Info("Using commitState (L1 stored blob hash matches sealed header)", + "batch_index", batchIndex, + "stored_blob_hash", common.Hash(storedBlobHash).Hex()) + } + // tip and cap tip, gasFeeCap, blobFee, head, err := r.GetGasTipAndCap() if err != nil { return fmt.Errorf("get gas tip and cap error:%v", err) } - // The official writer has one post-cutover path: the current commitBatch - // selector with a freshly constructed blob sidecar. - calldata, err := r.abi.Pack("commitBatch", rollupBatch) + // calldata encode — commitState reuses stored blob hash and must not carry blob data in tx + var calldata []byte + if useCommitState { + calldata, err = r.abi.Pack("commitState", rollupBatch, *signature) + } else { + calldata, err = r.abi.Pack("commitBatch", rollupBatch, *signature) + } if err != nil { return fmt.Errorf("pack calldata error:%v", err) } @@ -984,11 +1164,10 @@ func (r *Rollup) rollup() error { // is available during eth_estimateGas simulation. var estimateBlobHashes []common.Hash var estimateBlobFeeCap *big.Int - if len(rpcRollupBatch.Sidecar.Blobs) == 0 { - return fmt.Errorf("batch %d has no fresh blob sidecar", batchIndex) + if !useCommitState && len(rpcRollupBatch.Sidecar.Blobs) > 0 { + estimateBlobHashes = blob.BlobHashes(rpcRollupBatch.Sidecar.Blobs, rpcRollupBatch.Sidecar.Commitments) + estimateBlobFeeCap = blobFee } - estimateBlobHashes = blob.BlobHashes(rpcRollupBatch.Sidecar.Blobs, rpcRollupBatch.Sidecar.Commitments) - estimateBlobFeeCap = blobFee gas, err := r.EstimateGas(r.WalletAddr(), r.rollupAddr, calldata, gasFeeCap, tip, estimateBlobHashes, estimateBlobFeeCap) if err != nil { log.Warn("Estimate gas failed", "batch_index", batchIndex, "error", err) @@ -1014,7 +1193,13 @@ func (r *Rollup) rollup() error { return fmt.Errorf("failed to get next nonce") } - tx, err := r.createRollupTx(rpcRollupBatch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) + // Create and sign transaction (commitState is always type-2, never blob) + var tx *ethtypes.Transaction + if useCommitState { + tx, err = r.createDynamicFeeTx(nonce, gas, tip, gasFeeCap, calldata) + } else { + tx, err = r.createRollupTx(rpcRollupBatch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) + } if err != nil { return fmt.Errorf("failed to create rollup tx: %w", err) } @@ -1057,10 +1242,10 @@ func (r *Rollup) getNextNonce() uint64 { } func (r *Rollup) createRollupTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) { - if batch == nil || len(batch.Sidecar.Blobs) == 0 { - return nil, errors.New("official commitBatch requires a fresh blob sidecar") + if len(batch.Sidecar.Blobs) > 0 { + return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) } - return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head) + return r.createDynamicFeeTx(nonce, gas, tip, gasFeeCap, calldata) } func (r *Rollup) createBlobTx(rpcBatch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) { @@ -1102,20 +1287,72 @@ func (r *Rollup) createBlobTx(rpcBatch *eth.RPCRollupBatch, nonce, gas uint64, t }), nil } -// tryRebuildRollupCommitTx rebuilds an owned current commitBatch from the local -// batch cache. It deliberately ignores the old transaction's blob hash/sidecar -// and L1 stored-hash state, and always constructs a fresh blob sidecar. -func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeCap, blobFeeCap *big.Int, head *ethtypes.Header) (newTx *ethtypes.Transaction, handled bool, err error) { - if tx.To() == nil || *tx.To() != r.rollupAddr { - return nil, false, nil +func (r *Rollup) createDynamicFeeTx(nonce, gas uint64, tip, gasFeeCap *big.Int, calldata []byte) (*ethtypes.Transaction, error) { + return ethtypes.NewTx(ðtypes.DynamicFeeTx{ + ChainID: r.chainId, + Nonce: nonce, + GasTipCap: tip, + GasFeeCap: gasFeeCap, + Gas: gas, + To: &r.rollupAddr, + Data: calldata, + }), nil +} + +// validateStoredBlobAgainstSealedHeader requires L1 stored blob hash to match the sealed +// header blob field (offset 57). Sealed headers always carry a non-zero semantic value +// (e.g. EmptyVersionedHash); callers must not skip validation when the field decodes to zero. +func (r *Rollup) validateStoredBlobAgainstSealedHeader(stored [32]byte, batchIndex uint64) error { + if stored == ([32]byte{}) { + return nil + } + if !r.cfg.SealBatch || r.batchCache == nil { + return nil + } + header, ok := r.batchCache.GetSealedBatchHeader(batchIndex) + if !ok || header == nil { + return fmt.Errorf("commitState: sealed batch header %d not in cache", batchIndex) } - batchIndex, err := utils.ParseOwnedCommitBatchIndex(tx.Data(), r.abi) - if errors.Is(err, utils.ErrNotOwnedCommit) { + headerBlob, err := header.BlobCommitHash() + if err != nil { + return fmt.Errorf("commitState: batch %d header blob field: %w", batchIndex, err) + } + if common.Hash(stored) != headerBlob { + return fmt.Errorf( + "commitState: L1 stored blob hash %s != sealed header %s (batch %d)", + common.Hash(stored).Hex(), headerBlob.Hex(), batchIndex, + ) + } + return nil +} + +// tryRebuildRollupCommitTx aligns an in-flight commit-like tx with L1 blob-hash state: +// - stored blob versioned hash set -> must use commitState (no blob), upgrading commitBatch / blob txs +// - stored hash cleared -> must use commitBatch (+ blob sidecar when present), downgrading stale commitState +// +// Returns handled=true when newTx must be used and the default ReSubmitTx copy path must be skipped. +func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeCap, blobFeeCap *big.Int, head *ethtypes.Header) (newTx *ethtypes.Transaction, handled bool, err error) { + method := utils.ParseMethod(tx, r.abi) + if !constants.IsCommitLikeMethod(method) { return nil, false, nil } + batchIndex := utils.ParseParentBatchIndex(tx.Data()) + 1 + stored, err := r.Rollup.BatchBlobVersionedHashes(nil, big.NewInt(int64(batchIndex))) if err != nil { + return nil, false, err + } + if err := r.validateStoredBlobAgainstSealedHeader(stored, batchIndex); err != nil { return nil, true, err } + if stored != ([32]byte{}) { + if method == constants.MethodCommitState && tx.Type() == ethtypes.DynamicFeeTxType { + return nil, false, nil + } + } else { + if method == constants.MethodCommitBatch { + return nil, false, nil + } + } var rpcRollupBatch *eth.RPCRollupBatch exist := true @@ -1127,6 +1364,10 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC if err != nil || !exist || rpcRollupBatch == nil { return nil, true, fmt.Errorf("cannot rebuild rollup commit tx: batch %d not in cache (err=%v)", batchIndex, err) } + signature, err := r.buildSignatureInput(rpcRollupBatch) + if err != nil { + return nil, true, err + } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -1137,7 +1378,23 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC WithdrawalRoot: rpcRollupBatch.WithdrawRoot, } - calldata, err := r.abi.Pack("commitBatch", rollupBatch) + if stored != ([32]byte{}) { + calldata, err := r.abi.Pack("commitState", rollupBatch, *signature) + if err != nil { + return nil, true, err + } + newTx, err = r.createDynamicFeeTx(tx.Nonce(), tx.Gas(), tip, gasFeeCap, calldata) + if err != nil { + return nil, true, err + } + log.Info("Rebuilt pending rollup tx as commitState (stored blob hash on L1)", + "batch_index", batchIndex, + "old_tx_type", tx.Type(), + "old_method", method) + return newTx, true, nil + } + + calldata, err := r.abi.Pack("commitBatch", rollupBatch, *signature) if err != nil { return nil, true, err } @@ -1148,9 +1405,10 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC if err != nil { return nil, true, err } - log.Info("Rebuilt pending rollup tx as fresh-blob commitBatch", + log.Info("Rebuilt pending rollup tx as commitBatch (no stored blob hash on L1)", "batch_index", batchIndex, - "old_tx_type", tx.Type()) + "old_tx_type", tx.Type(), + "old_method", method) return newTx, true, nil } @@ -1170,6 +1428,15 @@ func (r *Rollup) logTxInfo(tx *ethtypes.Transaction, batchIndex uint64) { ) } +func (r *Rollup) buildSignatureInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { + sigData := bindings.IRollupBatchSignatureInput{ + SignedSequencersBitmap: common.Big0, + SequencerSets: batch.CurrentSequencerSetBytes, + Signature: []byte("0x"), + } + return &sigData, nil +} + func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Header, error) { head, err := r.L1Client.HeaderByNumber(context.Background(), nil) if err != nil { @@ -1231,12 +1498,35 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Head // PreCheck is run before the submitter to check whether the submitter can be started func (r *Rollup) PreCheck() error { - isActive, err := r.IsActive() + + // debug stakers + stakers, err := r.Staking.GetStakers(nil) + if err != nil { + log.Debug("get stakers error", "err", err) + } else { + log.Debug("stakers", "len", len(stakers)) + for _, s := range stakers { + log.Debug("staker", "addr", s.Hex()) + } + } + // debug active stakers + activeStakers, err := r.Staking.GetActiveStakers(nil) + if err != nil { + log.Debug("get active stakers error", "err", err) + } else { + log.Debug("active stakers", "len", len(activeStakers)) + for _, s := range activeStakers { + log.Debug("active staker", "addr", s.Hex()) + } + } + + isStaker, err := r.IsStaker() if err != nil { - return fmt.Errorf("check submitter qualification: %w", err) + return fmt.Errorf("check if this account is sequencer error:%v", err) } - if !isActive { - return fmt.Errorf("submitter %s is not active", r.WalletAddr().Hex()) + + if !isStaker { + return fmt.Errorf("this account is not staker, can not rollup") } return nil @@ -1262,7 +1552,7 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll log.Warn("failed to get batch", "error", err) continue } - if batch != nil { + if batch != nil && len(batch.Signatures) > 0 { return batch, nil } } @@ -1270,6 +1560,100 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll return nil, nil } +// query sequencer set from sequencer contract on l2 +func QuerySequencerSet(addr common.Address, clients []iface.L2Client) ([]common.Address, error) { + if len(clients) < 1 { + return nil, fmt.Errorf("no client to query sequencer set") + } + for _, client := range clients { + // l2 sequencer + l2Seqencer, err := bindings.NewSequencer(addr, client) + if err != nil { + log.Warn("failed to connect to sequencer", "error", err) + continue + } + // get sequencer set + seqSet, err := l2Seqencer.GetSequencerSet2(nil) + if err != nil { + log.Warn("failed to get sequencer set", "error", err) + continue + } + return seqSet, nil + } + return nil, fmt.Errorf("no sequencer set found after querying all clients") +} + +// query epoch from gov contract on l2 +func GetEpoch(addr common.Address, clients []iface.L2Client) (*big.Int, error) { + if len(clients) < 1 { + return nil, fmt.Errorf("no client to query epoch") + } + for _, client := range clients { + // l2 gov + l2Gov, err := bindings.NewGov(addr, client) + if err != nil { + log.Warn("failed to connect to gov", "error", err) + continue + } + // get epoch + epoch, err := l2Gov.RollupEpoch(nil) + if err != nil { + log.Warn("failed to get epoch", "error", err) + continue + } + return epoch, nil + } + return nil, fmt.Errorf("no epoch found after querying all clients") +} + +// query sequencer set update time from sequencer contract on l2 +func GetSequencerSetUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { + if len(clients) < 1 { + return nil, fmt.Errorf("no client to query sequencer set update time") + } + for _, client := range clients { + // l2 sequencer + l2Seqencer, err := bindings.NewSequencer(addr, client) + if err != nil { + log.Warn("failed to connect to sequencer", "error", err) + continue + } + // get sequencer set update time + updateTime, err := l2Seqencer.UpdateTime(nil) + if err != nil { + log.Warn("failed to get sequencer set update time", "error", err) + continue + } + return updateTime, nil + } + return nil, fmt.Errorf("no sequencer set update time found after querying all clients") +} + +// query epoch update time from gov contract on l2 +func GetEpochUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { + if len(clients) < 1 { + return nil, fmt.Errorf("no client to query epoch update time") + } + for _, client := range clients { + // l2 gov + l2Gov, err := bindings.NewGov(addr, client) + if err != nil { + log.Warn("failed to connect to gov", "error", err) + continue + } + // get epoch update time + updateTime, err := l2Gov.RollupEpochUpdateTime(nil) + if err != nil { + log.Warn("failed to get epoch update time", "error", err) + continue + } + return updateTime, nil + + } + return nil, fmt.Errorf("no epoch update time found after querying all clients") + +} + func UpdateGasLimit(tx *ethtypes.Transaction) (*ethtypes.Transaction, error) { // add buffer to gas limit (*1.2) newGasLimit := tx.Gas() * 12 / 10 @@ -1442,9 +1826,6 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr } else if err != nil { return nil, err } else { - if len(tx.Data()) != 0 && tx.To() != nil && *tx.To() == r.rollupAddr && utils.ParseMethod(tx, r.abi) != constants.MethodFinalizeBatch { - return nil, fmt.Errorf("refuse to resubmit non-owned rollup calldata (selector 0x%x)", tx.Data()[:min(4, len(tx.Data()))]) - } switch tx.Type() { case ethtypes.DynamicFeeTxType: newTx = ethtypes.NewTx(ðtypes.DynamicFeeTx{ @@ -1489,8 +1870,8 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr } } - // A malformed/non-blob owned record cannot pass strict journal recovery, but - // keep replacement robust if one is injected into memory by a test/tool. + // Original tx was not a blob tx, but rebuild (e.g. commitState -> commitBatch) may produce a blob tx. + // In that case blobFeeCap was never bumped above (bump only ran for BlobTxType). Apply the same bump as for blob replacements. if !resend && newTx != nil && newTx.Type() == ethtypes.BlobTxType && tx.Type() != ethtypes.BlobTxType { embeddedCap := newTx.BlobGasFeeCap() if embeddedCap != nil { @@ -1547,12 +1928,13 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr return newTx, nil } -func (r *Rollup) IsActive() (bool, error) { - isActive, err := r.Submitter.IsActive(nil, r.WalletAddr()) +func (r *Rollup) IsStaker() (bool, error) { + + isStaker, err := r.Staking.IsStaker(nil, r.WalletAddr()) if err != nil { - return false, fmt.Errorf("call Submitter.isActive: %w", err) + return false, fmt.Errorf("call IsStaker err :%v", err) } - return isActive, nil + return isStaker, nil } func (r *Rollup) EstimateGas( diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index 644a5d631..2c3bb3ed3 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -2,11 +2,11 @@ package services import ( "context" - "errors" "math/big" "testing" "time" + "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core" ethtypes "github.com/morph-l2/go-ethereum/core/types" @@ -14,8 +14,7 @@ import ( "github.com/stretchr/testify/require" "morph-l2/bindings/bindings" - commonbatch "morph-l2/common/batch" - "morph-l2/tx-submitter/db" + "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/metrics" "morph-l2/tx-submitter/mock" @@ -43,17 +42,47 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie metrics.UnregisterMetrics() }) - submitter := mock.NewMockSubmitter() + // Create mock event storage + eventStorage := mock.NewMockEventInfoStorage() + err = eventStorage.Load() + require.NoError(t, err) + + // Initialize event storage with test data + eventStorage.SetBlockProcessed(1000) + eventStorage.SetBlockTime(uint64(time.Now().Unix())) + err = eventStorage.Store() + require.NoError(t, err) + + // Create mock event indexer + indexer := event.NewEventIndexer( + nil, // We don't need a real ethclient.Client for testing + big.NewInt(0), + ethereum.FilterQuery{}, + 100, + eventStorage, + ) + + // Create mock rotator + rotator := NewRotator(common.Address{}, common.Address{}, indexer) + + // Create mock L1Staking + l1Staking := mock.NewMockL1Staking() + // Set some test stakers + testStakers := []common.Address{ + common.HexToAddress("0x1111111111111111111111111111111111111111"), + common.HexToAddress("0x2222222222222222222222222222222222222222"), + } + l1Staking.SetActiveStakers(testStakers) // Create rollup config defaultCfg := utils.Config{ - MaxTip: 10e9, - MaxBaseFee: 100e9, - MinTip: 1e9, - TipFeeBump: 100, - TxTimeout: 10 * time.Second, - BatchBlockInterval: 1, - MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) + MaxTip: 10e9, + MaxBaseFee: 100e9, + MinTip: 1e9, + TipFeeBump: 100, + TxTimeout: 10 * time.Second, + PriorityRollup: true, + MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) } // Create mock journal @@ -75,15 +104,17 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie l1Mock, []iface.L2Client{l2Mock}, mockRollup, - submitter, + l1Staking, big.NewInt(1), privateKey, common.Address{}, rollupAbi, defaultCfg, nil, + rotator, nil, nil, + eventStorage, nil, ) @@ -98,42 +129,6 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie return rollup, l1Mock, l2Mock, mockRollup } -func TestPreCheckUsesSubmitterIsActive(t *testing.T) { - r, _, _, _ := setupTestRollup(t) - submitter := r.Submitter.(*mock.MockSubmitter) - - require.NoError(t, r.PreCheck()) - require.Equal(t, r.WalletAddr(), submitter.LastQuery()) - - submitter.SetActive(r.WalletAddr(), false) - require.ErrorContains(t, r.PreCheck(), "is not active") -} - -func TestRollbackCanonicalBootstrapClearsCheckpoint(t *testing.T) { - ldb, err := db.New(t.TempDir()) - require.NoError(t, err) - t.Cleanup(func() { require.NoError(t, ldb.Close()) }) - require.NoError(t, ldb.PutBytes([]byte(commonbatch.SealedBatchIndicesKey), []byte("corrupt-checkpoint"))) - - cache := commonbatch.NewBatchCache( - nil, - nil, - 1, - commonbatch.BatchConfig{BlockInterval: 1}, - nil, - &iface.L2Clients{}, - nil, - nil, - ldb, - ) - r := &Rollup{batchCache: cache} - cause := errors.New("safe head changed") - err = r.rollbackCanonicalBootstrap("assemble downtime L2 blocks", cause) - require.ErrorIs(t, err, cause) - _, err = ldb.GetBytes([]byte(commonbatch.SealedBatchIndicesKey)) - require.Error(t, err, "failed startup must not leave a resumable checkpoint") -} - // TestHandleDiscardedTx tests the handling of discarded transactions func TestHandleDiscardedTx(t *testing.T) { r, l1Mock, _, _ := setupTestRollup(t) diff --git a/tx-submitter/services/rollup_test.go b/tx-submitter/services/rollup_test.go index 664f2de5b..79fe4fcd3 100644 --- a/tx-submitter/services/rollup_test.go +++ b/tx-submitter/services/rollup_test.go @@ -8,7 +8,6 @@ import ( "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto/kzg4844" - "github.com/morph-l2/go-ethereum/eth" "github.com/stretchr/testify/require" "morph-l2/tx-submitter/utils" @@ -105,7 +104,6 @@ func TestGetGasTipAndCap(t *testing.T) { } func TestReSubmitTx(t *testing.T) { - genericTo := common.HexToAddress("0x0000000000000000000000000000000000000001") marketTip := big.NewInt(3e9) // 3 Gwei market tip baseFee := big.NewInt(2e9) // 2 Gwei base fee block := types.NewBlockWithHeader( @@ -133,7 +131,7 @@ func TestReSubmitTx(t *testing.T) { GasTipCap: big.NewInt(2e9), // 2 Gwei GasFeeCap: big.NewInt(10e9), // 10 Gwei Gas: 100000, - To: &genericTo, + To: &common.Address{}, Value: big.NewInt(0), Data: []byte{1, 2, 3, 4}, }) @@ -190,7 +188,7 @@ func TestReSubmitTx(t *testing.T) { GasTipCap: uint256.MustFromBig(big.NewInt(2e9)), GasFeeCap: uint256.MustFromBig(big.NewInt(10e9)), Gas: 200000, - To: genericTo, + To: common.Address{}, Value: uint256.NewInt(0), Data: []byte{1, 2, 3, 4}, BlobFeeCap: uint256.MustFromBig(big.NewInt(5e9)), @@ -378,6 +376,7 @@ func TestTxStateTransition(t *testing.T) { // Create rollup instance rollup, l1Mock, _, _ := setupTestRollup(t) + rollup.cfg.PriorityRollup = true // Test transaction state transitions t.Run("Transaction State Flow", func(t *testing.T) { @@ -417,32 +416,3 @@ func TestTxStateTransition(t *testing.T) { require.Nil(t, txRecord) }) } - -func TestCreateRollupTxRequiresFreshBlobSidecar(t *testing.T) { - r, _, _, _ := setupTestRollup(t) - _, err := r.createRollupTx( - ð.RPCRollupBatch{}, - 1, - 100_000, - big.NewInt(1), - big.NewInt(2), - big.NewInt(1), - []byte{0x41, 0xf7, 0x56, 0xda}, - &types.Header{}, - ) - require.ErrorContains(t, err, "fresh blob sidecar") -} - -func TestReSubmitTxRejectsNonOwnedRollupCalldata(t *testing.T) { - r, l1Mock, _, _ := setupTestRollup(t) - l1Mock.Block = types.NewBlockWithHeader(&types.Header{BaseFee: big.NewInt(1)}) - tx := types.NewTx(&types.DynamicFeeTx{ - ChainID: big.NewInt(1), - GasTipCap: big.NewInt(1), - GasFeeCap: big.NewInt(2), - To: &r.rollupAddr, - Data: []byte{0xde, 0xad, 0xbe, 0xef}, - }) - _, err := r.ReSubmitTx(false, tx) - require.ErrorContains(t, err, "refuse to resubmit non-owned rollup calldata") -} diff --git a/tx-submitter/services/rotator.go b/tx-submitter/services/rotator.go new file mode 100644 index 000000000..bb5bb81af --- /dev/null +++ b/tx-submitter/services/rotator.go @@ -0,0 +1,158 @@ +package services + +import ( + "errors" + "fmt" + "math/big" + "sync" + "time" + + "morph-l2/tx-submitter/event" + "morph-l2/tx-submitter/iface" + "morph-l2/tx-submitter/utils" + + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/log" +) + +type Rotator struct { + // used to record the start time of rotation + // updated when the sequencerSet, stakingSet or epoch is updated + startTime *big.Int // timestamp + submitterSet []common.Address + sequencerSet []common.Address + epoch *big.Int // epoch for rotation + mu sync.Mutex // lock + l2SequencerAddr common.Address + l2GovAddr common.Address + indexer *event.EventIndexer +} + +func NewRotator(l2SeqencerAddr, l2GovAddr common.Address, indexer *event.EventIndexer) *Rotator { + return &Rotator{ + l2SequencerAddr: l2SeqencerAddr, + l2GovAddr: l2GovAddr, + indexer: indexer, + } +} + +func (r *Rotator) StartEventIndexer() { + go r.indexer.Index() +} + +// UpdateState updates the state of the rotator +// updated by event listener in the future +func (r *Rotator) UpdateState(clients []iface.L2Client, l1Staking iface.IL1Staking) error { + + epochUpdateTime, err := GetEpochUpdateTime(r.l2GovAddr, clients) + if err != nil { + log.Error("failed to get epoch update time", "err", err) + return fmt.Errorf("GetCurrentSubmitter: failed to get epoch update time: %w", err) + } + // sequencer set update time + sequcerUpdateTime, err := GetSequencerSetUpdateTime(r.l2SequencerAddr, clients) + if err != nil { + log.Error("failed to get sequencer set update time", "err", err) + return fmt.Errorf("GetCurrentSubmitter: failed to get sequencer set update time: %w", err) + } + + storage := r.indexer.GetStorage() + err = storage.Load() + if err != nil { + log.Error("failed to load storage", "err", err) + return fmt.Errorf("GetCurrentSubmitter: failed to load storage: %w", err) + } + // if index not complete + if storage.BlockProcessed() == 0 { + return errors.New("wait event index service to complete") + } + + r.startTime = utils.MaxOfThreeBig(epochUpdateTime, sequcerUpdateTime, big.NewInt(int64(storage.BlockTime()))) + + // get current sequencer set + seqSet, err := QuerySequencerSet(r.l2SequencerAddr, clients) + if err != nil { + log.Error("failed to get sequencer set", "err", err) + return fmt.Errorf("UpdateState: failed to get sequencer set: %w", err) + } + r.SetSequencerSet(seqSet) + // get current epoch + epoch, err := GetEpoch(r.l2GovAddr, clients) + if err != nil { + log.Error("failed to get epoch", "err", err) + return err + } + r.epoch = epoch + + // get l1staking active staker set + stakers, err := l1Staking.GetActiveStakers(nil) + if err != nil { + log.Error("failed to get active stakers", "err", err) + return fmt.Errorf("UpdateState: failed to get active stakers: %w", err) + } + submitterSet := utils.IntersectionOfAddresses(r.GetSequencerSet(), stakers) + r.SetSubmitterSet(submitterSet) + // rotator info + log.Info( + "rotator state updated", + "epoch", r.epoch, + "start_time", utils.FormatTime(r.startTime), + "start_timestamp", r.startTime, + "epoch_update_time", utils.FormatTime(epochUpdateTime), + "epoch_update_timestamp", epochUpdateTime, + "seq_update_time", utils.FormatTime(sequcerUpdateTime), + "seq_update_timestamp", sequcerUpdateTime, + "indexed_latest_block", storage.BlockProcessed(), + "indexed_event_time", utils.FormatTime(big.NewInt(int64(storage.BlockTime()))), + "indexed_event_timestamp", storage.BlockTime(), + ) + + return nil +} + +// GetCurrentSubmitter returns the current sequencer that should be submitting +func (r *Rotator) CurrentSubmitter(clients []iface.L2Client, l1Staking iface.IL1Staking) (*common.Address, int64, error) { + + err := r.UpdateState(clients, l1Staking) + if err != nil { + return nil, 0, fmt.Errorf("update state err: %w", err) + } + + if len(r.GetSubmitterSet()) == 0 { + return nil, 0, fmt.Errorf("GetCurrentSubmitter: sequencer set is empty") + } + + if r.epoch.Int64() == 0 { + return nil, 0, fmt.Errorf("GetCurrentSubmitter: epoch is 0") + } + + sec := time.Now().Unix() - r.startTime.Int64() + seqIdx := sec / r.epoch.Int64() % int64(len(r.GetSequencerSet())) + + return &r.GetSubmitterSet()[seqIdx], seqIdx, nil + +} + +func (r *Rotator) SetSubmitterSet(newSet []common.Address) { + r.mu.Lock() + defer r.mu.Unlock() + r.submitterSet = newSet +} +func (r *Rotator) GetSubmitterSet() []common.Address { + r.mu.Lock() + defer r.mu.Unlock() + return r.submitterSet +} + +func (r *Rotator) SetSequencerSet(newSet []common.Address) { + r.mu.Lock() + defer r.mu.Unlock() + r.sequencerSet = newSet +} + +func (r *Rotator) GetSequencerSet() []common.Address { + r.mu.Lock() + defer r.mu.Unlock() + return r.sequencerSet + +} diff --git a/tx-submitter/types/batch_cache.go b/tx-submitter/types/batch_cache.go index fd1cbe5c0..7ebe49b81 100644 --- a/tx-submitter/types/batch_cache.go +++ b/tx-submitter/types/batch_cache.go @@ -45,12 +45,21 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { return nil, false } - if fetchedBatch != nil { + // Validate batch before caching - batch must exist and have signatures + if fetchedBatch != nil && len(fetchedBatch.Signatures) > 0 { + // Store valid batch in cache for future use b.m.Lock() b.batchCache[batchIndex] = fetchedBatch b.m.Unlock() return fetchedBatch, true + } else if fetchedBatch != nil { + // Batch exists but doesn't have signatures, don't cache it + log.Debug("Batch validation failed - no signatures", + "batch_index", batchIndex, + "found", fetchedBatch != nil, + "has_signatures", len(fetchedBatch.Signatures) > 0) + return fetchedBatch, true } } @@ -58,8 +67,12 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { } func (b *BatchCacheLegacy) Set(batchIndex uint64, batch *eth.RPCRollupBatch) { - if batch == nil { - log.Debug("Refusing to cache nil batch", "batch_index", batchIndex) + // Validate batch before caching - batch must exist and have signatures + if batch == nil || len(batch.Signatures) == 0 { + log.Debug("Refusing to cache invalid batch", + "batch_index", batchIndex, + "exists", batch != nil, + "has_signatures", batch != nil && len(batch.Signatures) > 0) return } diff --git a/tx-submitter/utils/config.go b/tx-submitter/utils/config.go index 3a1520636..4e9269f95 100644 --- a/tx-submitter/utils/config.go +++ b/tx-submitter/utils/config.go @@ -1,13 +1,10 @@ package utils import ( - "encoding/json" - "fmt" "time" "github.com/urfave/cli" - "morph-l2/common/batch" "morph-l2/tx-submitter/flags" ) @@ -31,13 +28,8 @@ type Config struct { // RollupAddress is the Rollup contract address. RollupAddress string - // SubmitterAddress is the Submitter qualification and stake contract. - SubmitterAddress string - - // Static batch sealing configuration. Values are snapshotted before cutover - // and must remain identical across the working and standby instances. - BatchBlockInterval uint64 - BatchTimeout uint64 + // StakingAddress + L1StakingAddress string // PollInterval is the delay between querying L2 for more transaction // and creating a new batch. @@ -54,11 +46,18 @@ type Config struct { // finalize // if start finalize Finalize bool + // L2 contract + L2SequencerAddress string + L2GovAddress string + // metrics MetricsServerEnable bool MetricsHostname string MetricsPort uint64 + // decentralized + PriorityRollup bool + // tx fee limit TxFeeLimit uint64 @@ -83,10 +82,6 @@ type Config struct { // journal file path JournalFilePath string - // BatchConfigPreflight prints the effective static batch configuration and exits. - BatchConfigPreflight bool - BatchConfigSourceBlockNumber uint64 - BatchConfigSourceBlockHash string // tip bump TipFeeBump uint64 MaxTip uint64 @@ -104,6 +99,14 @@ type Config struct { ExternalSignRsaPriv string // rough estimate gas switch RoughEstimateGas bool + // rotator interval buffer + RotatorBuffer int64 + // listener process path + StakingEventStoreFilename string + // l1 staking deployed block number + L1StakingDeployedBlockNumber uint64 + // event indexer index step + EventIndexStep uint64 // leveldb path name LeveldbPathName string BlockNotIncreasedThreshold int64 @@ -115,39 +118,6 @@ type Config struct { BatchV2UpgradeTime uint64 } -// BatchConfig returns the immutable configuration consumed by common/batch. -func (c Config) BatchConfig() batch.BatchConfig { - return batch.BatchConfig{ - BlockInterval: c.BatchBlockInterval, - Timeout: c.BatchTimeout, - } -} - -// BatchConfigReport is the stable, machine-readable preflight output used by -// operators to compare all working and standby instances before cutover. -type BatchConfigReport struct { - BlockInterval uint64 `json:"batch_block_interval"` - Timeout uint64 `json:"batch_timeout"` - SourceBlockNumber uint64 `json:"source_block_number"` - SourceBlockHash string `json:"source_block_hash"` - Hash string `json:"config_hash"` -} - -func (c Config) BatchConfigReport() BatchConfigReport { - bc := c.BatchConfig() - return BatchConfigReport{ - BlockInterval: bc.BlockInterval, - Timeout: bc.Timeout, - SourceBlockNumber: c.BatchConfigSourceBlockNumber, - SourceBlockHash: c.BatchConfigSourceBlockHash, - Hash: bc.Hash().Hex(), - } -} - -func (c Config) BatchConfigReportJSON() ([]byte, error) { - return json.Marshal(c.BatchConfigReport()) -} - // NewConfig parses the DriverConfig from the provided flags or environment variables. // This method fails if ValidateConfig deems the configuration to be malformed. func NewConfig(ctx *cli.Context) (Config, error) { @@ -161,15 +131,18 @@ func NewConfig(ctx *cli.Context) (Config, error) { TxTimeout: ctx.GlobalDuration(flags.TxTimeoutFlag.Name), // finalize Finalize: ctx.GlobalBool(flags.FinalizeFlag.Name), - // L1 contracts and static batch configuration - SubmitterAddress: ctx.GlobalString(flags.SubmitterAddressFlag.Name), - RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), - BatchBlockInterval: ctx.GlobalUint64(flags.BatchBlockIntervalFlag.Name), - BatchTimeout: ctx.GlobalUint64(flags.BatchTimeoutFlag.Name), + // L1 contract + L1StakingAddress: ctx.GlobalString(flags.L1StakingAddressFlag.Name), + RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), + // L2 contract + L2SequencerAddress: ctx.GlobalString(flags.L2SequencerAddressFlag.Name), + L2GovAddress: ctx.GlobalString(flags.L2GovAddressFlag.Name), // metrics MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnable.Name), MetricsHostname: ctx.GlobalString(flags.MetricsHostname.Name), MetricsPort: ctx.GlobalUint64(flags.MetricsPort.Name), + // decentralized + PriorityRollup: ctx.GlobalBool(flags.PriorityRollupFlag.Name), // tx config TxFeeLimit: ctx.GlobalUint64(flags.TxFeeLimitFlag.Name), @@ -187,15 +160,12 @@ func NewConfig(ctx *cli.Context) (Config, error) { GasLimitBuffer: ctx.GlobalUint64(flags.GasLimitBuffer.Name), - JournalFilePath: ctx.GlobalString(flags.JournalFlag.Name), - BatchConfigPreflight: ctx.GlobalBool(flags.BatchConfigPreflightFlag.Name), - BatchConfigSourceBlockNumber: ctx.GlobalUint64(flags.BatchConfigSourceBlockNumberFlag.Name), - BatchConfigSourceBlockHash: ctx.GlobalString(flags.BatchConfigSourceBlockHashFlag.Name), - TipFeeBump: ctx.GlobalUint64(flags.TipFeeBumpFlag.Name), - MaxTip: ctx.GlobalUint64(flags.MaxTipFlag.Name), - MinTip: ctx.GlobalUint64(flags.MinTipFlag.Name), - MaxBaseFee: ctx.GlobalUint64(flags.MaxBaseFeeFlag.Name), - MaxTxsInPendingPool: ctx.GlobalUint64(flags.MaxTxsInPendingPoolFlag.Name), + JournalFilePath: ctx.GlobalString(flags.JournalFlag.Name), + TipFeeBump: ctx.GlobalUint64(flags.TipFeeBumpFlag.Name), + MaxTip: ctx.GlobalUint64(flags.MaxTipFlag.Name), + MinTip: ctx.GlobalUint64(flags.MinTipFlag.Name), + MaxBaseFee: ctx.GlobalUint64(flags.MaxBaseFeeFlag.Name), + MaxTxsInPendingPool: ctx.GlobalUint64(flags.MaxTxsInPendingPoolFlag.Name), // external sign ExternalSign: ctx.GlobalBool(flags.ExternalSign.Name), @@ -206,6 +176,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { ExternalSignRsaPriv: ctx.GlobalString(flags.ExternalSignRsaPriv.Name), // rough estimate gas switch RoughEstimateGas: ctx.GlobalBool(flags.RoughEstimateGasFlag.Name), + // rotator interval buffer + RotatorBuffer: ctx.GlobalInt64(flags.RotatorBufferFlag.Name), + + // path + StakingEventStoreFilename: ctx.GlobalString(flags.StakingEventStoreFileFlag.Name), + // l1 staking deployed block number + L1StakingDeployedBlockNumber: ctx.GlobalUint64(flags.L1StakingDeployedBlocknumFlag.Name), + // index step + EventIndexStep: ctx.GlobalUint64(flags.EventIndexStepFlag.Name), // leveldb path name LeveldbPathName: ctx.GlobalString(flags.LeveldbPathNameFlag.Name), // BlockNotIncreasedThreshold @@ -218,9 +197,5 @@ func NewConfig(ctx *cli.Context) (Config, error) { BatchV2UpgradeTime: ctx.GlobalUint64(flags.BatchV2UpgradeTimeFlag.Name), } - if err := cfg.BatchConfig().Validate(); err != nil { - return Config{}, fmt.Errorf("invalid static batch configuration: %w", err) - } - return cfg, nil } diff --git a/tx-submitter/utils/config_test.go b/tx-submitter/utils/config_test.go deleted file mode 100644 index 08f53f76a..000000000 --- a/tx-submitter/utils/config_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package utils - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestConfigBatchConfig(t *testing.T) { - tests := []struct { - name string - cfg Config - wantErr bool - }{ - {name: "interval only", cfg: Config{BatchBlockInterval: 10}}, - {name: "timeout only", cfg: Config{BatchTimeout: 60}}, - {name: "both", cfg: Config{BatchBlockInterval: 10, BatchTimeout: 60}}, - {name: "both zero", cfg: Config{}, wantErr: true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.wantErr, tt.cfg.BatchConfig().Validate() != nil) - }) - } -} - -func TestBatchConfigReportIncludesSourceAndStableHash(t *testing.T) { - cfg := Config{ - BatchBlockInterval: 10, - BatchTimeout: 60, - BatchConfigSourceBlockNumber: 123, - BatchConfigSourceBlockHash: "0xabc", - } - report := cfg.BatchConfigReport() - require.Equal(t, uint64(10), report.BlockInterval) - require.Equal(t, uint64(60), report.Timeout) - require.Equal(t, uint64(123), report.SourceBlockNumber) - require.Equal(t, "0xabc", report.SourceBlockHash) - require.Equal(t, cfg.BatchConfig().Hash().Hex(), report.Hash) -} diff --git a/tx-submitter/utils/utils.go b/tx-submitter/utils/utils.go index 2b82fe4b3..7001e5dae 100644 --- a/tx-submitter/utils/utils.go +++ b/tx-submitter/utils/utils.go @@ -4,9 +4,9 @@ import ( "bytes" "context" "encoding/binary" - "errors" "fmt" "math/big" + "reflect" "regexp" "strconv" "time" @@ -20,70 +20,6 @@ import ( "github.com/morph-l2/go-ethereum/log" ) -var ErrNotOwnedCommit = errors.New("calldata is not an owned current commitBatch") - -// ParseOwnedCommit accepts only the current, post-cutover commitBatch selector. -// Historical commitBatch, commitState, commitBatchWithProof, and unknown -// calldata must never be imported into the official writer's pending state. -func ParseOwnedCommit(data []byte, current *abi.ABI) (methodName string, input *bindings.IRollupBatchDataInput, err error) { - if current == nil || len(data) < 4 { - return "", nil, ErrNotOwnedCommit - } - method, ok := current.Methods["commitBatch"] - if !ok || !bytes.Equal(data[:4], method.ID) { - return "", nil, ErrNotOwnedCommit - } - values, err := method.Inputs.Unpack(data[4:]) - if err != nil || len(values) != 1 { - if err == nil { - err = errors.New("unexpected commitBatch argument count") - } - return "", nil, fmt.Errorf("decode owned commitBatch: %w", err) - } - defer func() { - if recovered := recover(); recovered != nil { - methodName = "" - input = nil - err = fmt.Errorf("decode owned commitBatch tuple: %v", recovered) - } - }() - converted := abi.ConvertType(values[0], new(bindings.IRollupBatchDataInput)) - input, ok = converted.(*bindings.IRollupBatchDataInput) - if !ok || input == nil { - return "", nil, errors.New("decode owned commitBatch: invalid batch tuple") - } - return method.Name, input, nil -} - -func ParseOwnedCommitBatchIndex(data []byte, current *abi.ABI) (uint64, error) { - _, input, err := ParseOwnedCommit(data, current) - if err != nil { - return 0, err - } - if len(input.ParentBatchHeader) < 9 { - return 0, errors.New("owned commitBatch parent header is too short") - } - parentIndex := binary.BigEndian.Uint64(input.ParentBatchHeader[1:9]) - if parentIndex == ^uint64(0) { - return 0, errors.New("owned commitBatch parent index overflows") - } - return parentIndex + 1, nil -} - -// ParseParentBatchIndex is retained for non-authoritative diagnostics. It is -// strict: only the current commitBatch selector is accepted. -func ParseParentBatchIndex(data []byte) uint64 { - current, err := bindings.RollupMetaData.GetAbi() - if err != nil { - return 0 - } - batchIndex, err := ParseOwnedCommitBatchIndex(data, current) - if err != nil || batchIndex == 0 { - return 0 - } - return batchIndex - 1 -} - // Loop Run the f func periodically. func Loop(ctx context.Context, period time.Duration, f func()) { tick := time.NewTicker(period) @@ -127,6 +63,50 @@ func ParseFBatchIndex(calldata []byte) uint64 { return binary.BigEndian.Uint64(batchBytes[1:9]) } +func ParseParentBatchIndex(calldata []byte) uint64 { + /// * Field Bytes Type Index Comments + /// * version 1 uint8 0 The batch version + /// * batchIndex 8 uint64 1 The index of the batch + /// * l1MessagePopped 8 uint64 9 Number of L1 messages popped in the batch + + if len(calldata) < 4 { + return 0 + } + rollupAbi, err := bindings.RollupMetaData.GetAbi() + if err != nil { + return 0 + } + sel := calldata[:4] + var method abi.Method + var ok bool + if bytes.Equal(sel, rollupAbi.Methods["commitState"].ID) { + method, ok = rollupAbi.Methods["commitState"] + } else if bytes.Equal(sel, rollupAbi.Methods["commitBatch"].ID) { + method, ok = rollupAbi.Methods["commitBatch"] + } else { + // Unknown selector: keep legacy behavior (unpack as commitBatch). Matches older fixtures and + // any tx whose first tuple matches BatchDataInput layout even if the selector differs. + method, ok = rollupAbi.Methods["commitBatch"] + } + if !ok { + return 0 + } + parms, err := method.Inputs.UnpackValues(calldata[4:]) + if err != nil || len(parms) == 0 { + return 0 + } + v := reflect.ValueOf(parms[0]) + pbh := v.FieldByName("ParentBatchHeader") + if !pbh.IsValid() { + return 0 + } + b := pbh.Bytes() + if len(b) < 9 { + return 0 + } + return binary.BigEndian.Uint64(b[1:9]) +} + // SetFBatchIndex sets the batch index in the calldata while preserving all other data func SetFBatchIndex(calldata []byte, batchIndex uint64) error { if len(calldata) < 4 { @@ -172,14 +152,18 @@ func ParseBusinessInfo(tx *types.Transaction, a *abi.ABI) []interface{} { // var batchIndex uint64 // var finalizedIndex uint64 var res []interface{} - if len(tx.Data()) >= 4 { + if len(tx.Data()) > 0 { id := tx.Data()[:4] if bytes.Equal(id, a.Methods["commitBatch"].ID) { method := "commitBatch" - batchIndex, err := ParseOwnedCommitBatchIndex(tx.Data(), a) - if err != nil { - return []interface{}{} - } + batchIndex := ParseParentBatchIndex(tx.Data()) + 1 + res = append(res, + "method", method, + "batchIndex", batchIndex, + ) + } else if bytes.Equal(id, a.Methods["commitState"].ID) { + method := "commitState" + batchIndex := ParseParentBatchIndex(tx.Data()) + 1 res = append(res, "method", method, "batchIndex", batchIndex, @@ -211,6 +195,8 @@ func ParseMethod(tx *types.Transaction, a *abi.ABI) string { id := tx.Data()[:4] if bytes.Equal(id, a.Methods["commitBatch"].ID) { return "commitBatch" + } else if bytes.Equal(id, a.Methods["commitState"].ID) { + return "commitState" } else if bytes.Equal(id, a.Methods["finalizeBatch"].ID) { return "finalizeBatch" } else { diff --git a/tx-submitter/utils/utils_test.go b/tx-submitter/utils/utils_test.go index 8b9eea4b5..75f2382f2 100644 --- a/tx-submitter/utils/utils_test.go +++ b/tx-submitter/utils/utils_test.go @@ -8,11 +8,11 @@ import ( ) // test ParseBatchIndex -func TestParseParentBatchIndexRejectsLegacyCalldata(t *testing.T) { +func TestParseBatchIndex(t *testing.T) { calldata := "4a8d544f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000008f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e02c48c62b7604ecf508766324cd85afdc5faeb86de53f12dee5c24c7e25957b02018f517672a7760905227d4f085cf88d82b4793497846bb366b6cedd69af06aae5857a041c5a53ed68439ff4c9b8a79b9b749eb93f1e07ed07f58d60ebcf737300000000000000000000000000000000000000000000000000000000000000f900000000000000377b00000000000000000000000000001d987eb22c17eea2e2e3f3756599686586cbc42883ceedded826bc8508c13539cf6e017301c53247c7de720dd18b7d668cbcc17cb711a7aae46fbc43224203e0bca62c74b38e4c32df8e0656c3bd6acedc0ec57684327c99d10a1247f00ab8d3dece2c48c62b7604ecf508766324cd85afdc5faeb86de53f12dee5c24c7e25957b02e5857a041c5a53ed68439ff4c9b8a79b9b749eb93f1e07ed07f58d60ebcf7373a4d7461c3b8d74650efdca322d5fe15e699d534ee47ec9321bcb82bc7a9ec6e97bf7c21d9929b9d5d906a163a1dd8e74341ef11f7b84681b67d76953ee6ee3fb000000000000000000000000000000000000000000000000000000000000000000000000008ca2025800000000006acc320000000067d1c5aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc330000000067d1c5ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc340000000067d1c5ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc350000000067d1c5ad00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc360000000067d1c5ae00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc370000000067d1c5af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc380000000067d1c5b000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acc390000000067d1c5b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3a0000000067d1c5b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc3b0000000067d1c5b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3c0000000067d1c5b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3d0000000067d1c5b600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc3e0000000067d1c5b700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc3f0000000067d1c5b900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc400000000067d1c5ba00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc410000000067d1c5bc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc420000000067d1c5bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc430000000067d1c5be00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc440000000067d1c5bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc450000000067d1c5c000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc460000000067d1c5c100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc470000000067d1c5c200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc480000000067d1c5c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc490000000067d1c5c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4a0000000067d1c5c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4b0000000067d1c5c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc4c0000000067d1c5c700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4d0000000067d1c5c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc4e0000000067d1c5c900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc4f0000000067d1c5ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc500000000067d1c5cc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc510000000067d1c5cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc520000000067d1c5ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc530000000067d1c5cf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc540000000067d1c5d000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800005000000000000006acc550000000067d1c5d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc560000000067d1c5d200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc570000000067d1c5d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc580000000067d1c5d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc590000000067d1c5d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc5a0000000067d1c5d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5b0000000067d1c5d700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5c0000000067d1c5d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc5d0000000067d1c5d900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc5e0000000067d1c5da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc5f0000000067d1c5db00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc600000000067d1c5dc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc610000000067d1c5dd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc620000000067d1c5de00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc630000000067d1c5df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc640000000067d1c5e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc650000000067d1c5e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc660000000067d1c5e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc670000000067d1c5e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc680000000067d1c5e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc690000000067d1c5e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6a0000000067d1c5e700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6b0000000067d1c5e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6c0000000067d1c5e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc6d0000000067d1c5ea00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc6e0000000067d1c5eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc6f0000000067d1c5ec00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc700000000067d1c5ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc710000000067d1c5ee00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc720000000067d1c5ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc730000000067d1c5f000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc740000000067d1c5f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc750000000067d1c5f400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc760000000067d1c5f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc770000000067d1c5f600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc780000000067d1c5f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc790000000067d1c5f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7a0000000067d1c5f900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7b0000000067d1c5fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc7c0000000067d1c5fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7d0000000067d1c5fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7e0000000067d1c5fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc7f0000000067d1c5ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc800000000067d1c60000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc810000000067d1c60200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc820000000067d1c60300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc830000000067d1c60400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc840000000067d1c60600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc850000000067d1c60700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc860000000067d1c60800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc870000000067d1c60a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc880000000067d1c60c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc890000000067d1c60e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8a0000000067d1c60f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc8b0000000067d1c61000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc8c0000000067d1c61200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8d0000000067d1c61300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc8e0000000067d1c61400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc8f0000000067d1c61500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc900000000067d1c61600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc910000000067d1c61700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc920000000067d1c61800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc930000000067d1c61900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc940000000067d1c61a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc950000000067d1c61b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc960000000067d1c61d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc970000000067d1c61e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc980000000067d1c61f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc990000000067d1c62000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9a0000000067d1c62100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9b0000000067d1c62200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acc9c0000000067d1c62300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9d0000000067d1c62500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acc9e0000000067d1c62600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acc9f0000000067d1c62700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca00000000067d1c62800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca10000000067d1c62a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca20000000067d1c62b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca30000000067d1c62c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca40000000067d1c62d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca50000000067d1c62e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca60000000067d1c63000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca70000000067d1c63300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acca80000000067d1c63400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acca90000000067d1c63600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accaa0000000067d1c63900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accab0000000067d1c63a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accac0000000067d1c63d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accad0000000067d1c63e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accae0000000067d1c63f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accaf0000000067d1c64100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb00000000067d1c64300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb10000000067d1c64500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accb20000000067d1c64700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb30000000067d1c64900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb40000000067d1c64b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb50000000067d1c64c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb60000000067d1c64e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb70000000067d1c64f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb80000000067d1c65000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accb90000000067d1c65200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accba0000000067d1c65300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbb0000000067d1c65400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbc0000000067d1c65500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbd0000000067d1c65600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbe0000000067d1c65700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accbf0000000067d1c65900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc00000000067d1c65a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accc10000000067d1c65b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc20000000067d1c65c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc30000000067d1c65d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc40000000067d1c65e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc50000000067d1c65f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc60000000067d1c66000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accc70000000067d1c66100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc80000000067d1c66200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accc90000000067d1c66300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accca0000000067d1c66400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acccb0000000067d1c66500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acccc0000000067d1c66600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acccd0000000067d1c66700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accce0000000067d1c66800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acccf0000000067d1c66900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd00000000067d1c66a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd10000000067d1c66b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd20000000067d1c66c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd30000000067d1c66d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd40000000067d1c66e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd50000000067d1c66f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd60000000067d1c67000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accd70000000067d1c67200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd80000000067d1c67300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accd90000000067d1c67400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accda0000000067d1c67500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdb0000000067d1c67600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdc0000000067d1c67700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdd0000000067d1c67800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accde0000000067d1c67900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accdf0000000067d1c67a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce00000000067d1c67b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce10000000067d1c67c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce20000000067d1c67d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce30000000067d1c67e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce40000000067d1c67f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce50000000067d1c68000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce60000000067d1c68100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce70000000067d1c68200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acce80000000067d1c68300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acce90000000067d1c68400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accea0000000067d1c68500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acceb0000000067d1c68600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accec0000000067d1c68700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acced0000000067d1c68800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accee0000000067d1c68900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accef0000000067d1c68b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf00000000067d1c68d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf10000000067d1c68e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf20000000067d1c68f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf30000000067d1c69000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006accf40000000067d1c69100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf50000000067d1c69200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accf60000000067d1c69300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accf70000000067d1c69400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf80000000067d1c69500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accf90000000067d1c69600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accfa0000000067d1c69700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfb0000000067d1c69800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfc0000000067d1c69900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfd0000000067d1c69a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006accfe0000000067d1c69b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006accff0000000067d1c69c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd000000000067d1c69d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd010000000067d1c69e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd020000000067d1c69f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd030000000067d1c6a000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd040000000067d1c6a100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd050000000067d1c6a300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd060000000067d1c6a400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd070000000067d1c6a500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd080000000067d1c6a600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd090000000067d1c6a700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0a0000000067d1c6a800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd0b0000000067d1c6a900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0c0000000067d1c6aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd0d0000000067d1c6ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0e0000000067d1c6ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd0f0000000067d1c6af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd100000000067d1c6b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd110000000067d1c6b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd120000000067d1c6b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd130000000067d1c6b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd140000000067d1c6b800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd150000000067d1c6bb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd160000000067d1c6bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd170000000067d1c6bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd180000000067d1c6c100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd190000000067d1c6c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1a0000000067d1c6c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1b0000000067d1c6c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1c0000000067d1c6c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1d0000000067d1c6c700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1e0000000067d1c6c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd1f0000000067d1c6ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd200000000067d1c6cb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd210000000067d1c6cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd220000000067d1c6ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd230000000067d1c6cf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd240000000067d1c6d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd250000000067d1c6d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd260000000067d1c6d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd270000000067d1c6d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd280000000067d1c6d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd290000000067d1c6d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2a0000000067d1c6da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2b0000000067d1c6dc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd2c0000000067d1c6de00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2d0000000067d1c6df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2e0000000067d1c6e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd2f0000000067d1c6e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd300000000067d1c6e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd310000000067d1c6e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd320000000067d1c6e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd330000000067d1c6e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd340000000067d1c6e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd350000000067d1c6e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd360000000067d1c6eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd370000000067d1c6ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd380000000067d1c6ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd390000000067d1c6f100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3a0000000067d1c6f200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3b0000000067d1c6f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3c0000000067d1c6f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3d0000000067d1c6f600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3e0000000067d1c6f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd3f0000000067d1c6f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd400000000067d1c6fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd410000000067d1c6fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd420000000067d1c6fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd430000000067d1c6fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd440000000067d1c6fe00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd450000000067d1c6ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd460000000067d1c70000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd470000000067d1c70100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd480000000067d1c70200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd490000000067d1c70300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4a0000000067d1c70400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4b0000000067d1c70500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4c0000000067d1c70600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4d0000000067d1c70700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4e0000000067d1c70800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd4f0000000067d1c70900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd500000000067d1c70b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd510000000067d1c70c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd520000000067d1c70d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd530000000067d1c70e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd540000000067d1c70f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd550000000067d1c71000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd560000000067d1c71100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd570000000067d1c71300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd580000000067d1c71500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd590000000067d1c71600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd5a0000000067d1c71700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5b0000000067d1c71800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd5c0000000067d1c71900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5d0000000067d1c71a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acd5e0000000067d1c71b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd5f0000000067d1c71c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd600000000067d1c71d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd610000000067d1c71e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd620000000067d1c71f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd630000000067d1c72000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd640000000067d1c72100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd650000000067d1c72200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd660000000067d1c72300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd670000000067d1c72400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd680000000067d1c72500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd690000000067d1c72600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd6a0000000067d1c72700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6b0000000067d1c72800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6c0000000067d1c72900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd6d0000000067d1c72a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd6e0000000067d1c72b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006acd6f0000000067d1c72c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd700000000067d1c72e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd710000000067d1c72f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd720000000067d1c73000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd730000000067d1c73100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd740000000067d1c73200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd750000000067d1c73300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd760000000067d1c73400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd770000000067d1c73500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd780000000067d1c73600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd790000000067d1c73700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd7a0000000067d1c73800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd7b0000000067d1c73900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7c0000000067d1c73a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7d0000000067d1c73b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd7e0000000067d1c73c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd7f0000000067d1c73e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd800000000067d1c73f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd810000000067d1c74000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd820000000067d1c74100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd830000000067d1c74200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd840000000067d1c74300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd850000000067d1c74400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd860000000067d1c74500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd870000000067d1c74600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd880000000067d1c74700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acd890000000067d1c74800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8a0000000067d1c74900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acd8b0000000067d1c74a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8c0000000067d1c74b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8d0000000067d1c74c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8e0000000067d1c74d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd8f0000000067d1c74f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd900000000067d1c75000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd910000000067d1c75100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd920000000067d1c75200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd930000000067d1c75300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd940000000067d1c75500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd950000000067d1c75600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd960000000067d1c75700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd970000000067d1c75800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd980000000067d1c75900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd990000000067d1c75a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9a0000000067d1c75b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9b0000000067d1c75c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9c0000000067d1c75d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9d0000000067d1c75e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9e0000000067d1c75f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acd9f0000000067d1c76000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acda00000000067d1c76200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda10000000067d1c76300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acda20000000067d1c76500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda30000000067d1c76600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda40000000067d1c76700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda50000000067d1c76800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda60000000067d1c76a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda70000000067d1c76b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda80000000067d1c76c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acda90000000067d1c76d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdaa0000000067d1c76e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdab0000000067d1c76f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdac0000000067d1c77000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdad0000000067d1c77100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdae0000000067d1c77200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdaf0000000067d1c77300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb00000000067d1c77400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb10000000067d1c77500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb20000000067d1c77600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb30000000067d1c77700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb40000000067d1c77800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb50000000067d1c77900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb60000000067d1c77a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdb70000000067d1c77b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb80000000067d1c77c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdb90000000067d1c77e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdba0000000067d1c78000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbb0000000067d1c78200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbc0000000067d1c78300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbd0000000067d1c78400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbe0000000067d1c78600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdbf0000000067d1c78700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc00000000067d1c78800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc10000000067d1c78b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc20000000067d1c78c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc30000000067d1c78d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc40000000067d1c78f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc50000000067d1c79100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc60000000067d1c79300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc70000000067d1c79400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc80000000067d1c79500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdc90000000067d1c79700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdca0000000067d1c79800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdcb0000000067d1c79900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdcc0000000067d1c79b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdcd0000000067d1c79c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdce0000000067d1c79e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdcf0000000067d1c79f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd00000000067d1c7a000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd10000000067d1c7a200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd20000000067d1c7a400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd30000000067d1c7a600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd40000000067d1c7a700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd50000000067d1c7a800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd60000000067d1c7a900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd70000000067d1c7aa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd80000000067d1c7ab00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdd90000000067d1c7ac00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdda0000000067d1c7ad00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acddb0000000067d1c7ae00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acddc0000000067d1c7af00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acddd0000000067d1c7b000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdde0000000067d1c7b100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acddf0000000067d1c7b200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde00000000067d1c7b300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde10000000067d1c7b500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde20000000067d1c7b700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde30000000067d1c7b800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde40000000067d1c7b900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde50000000067d1c7bb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde60000000067d1c7bc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde70000000067d1c7bd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acde80000000067d1c7bf00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acde90000000067d1c7c000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdea0000000067d1c7c200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdeb0000000067d1c7c300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdec0000000067d1c7c400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acded0000000067d1c7c500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006acdee0000000067d1c7c600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdef0000000067d1c7c800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf00000000067d1c7c900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdf10000000067d1c7ca00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf20000000067d1c7cb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf30000000067d1c7cc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf40000000067d1c7cd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf50000000067d1c7ce00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf60000000067d1c7d000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf70000000067d1c7d100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf80000000067d1c7d200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdf90000000067d1c7d300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfa0000000067d1c7d400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006acdfb0000000067d1c7d500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfc0000000067d1c7d600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfd0000000067d1c7d700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdfe0000000067d1c7d800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006acdff0000000067d1c7d900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace000000000067d1c7da00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace010000000067d1c7db00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace020000000067d1c7dd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace030000000067d1c7df00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace040000000067d1c7e000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace050000000067d1c7e100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800005000000000000006ace060000000067d1c7e200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace070000000067d1c7e300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace080000000067d1c7e400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace090000000067d1c7e500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace0a0000000067d1c7e600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0b0000000067d1c7e700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0c0000000067d1c7e800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0d0000000067d1c7e900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace0e0000000067d1c7ea00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace0f0000000067d1c7eb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace100000000067d1c7ec00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace110000000067d1c7ed00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace120000000067d1c7ee00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace130000000067d1c7ef00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace140000000067d1c7f000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace150000000067d1c7f100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace160000000067d1c7f200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace170000000067d1c7f300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace180000000067d1c7f400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace190000000067d1c7f500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1a0000000067d1c7f700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1b0000000067d1c7f800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1c0000000067d1c7f900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1d0000000067d1c7fa00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace1e0000000067d1c7fb00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace1f0000000067d1c7fc00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace200000000067d1c7fd00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace210000000067d1c7fe00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace220000000067d1c7ff00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace230000000067d1c80000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace240000000067d1c80100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace250000000067d1c80200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace260000000067d1c80300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace270000000067d1c80400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace280000000067d1c80500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace290000000067d1c80600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2a0000000067d1c80800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2b0000000067d1c80900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2c0000000067d1c80a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2d0000000067d1c80c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2e0000000067d1c80d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace2f0000000067d1c80e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace300000000067d1c81000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace310000000067d1c81100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace320000000067d1c81200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace330000000067d1c81300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace340000000067d1c81400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace350000000067d1c81500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace360000000067d1c81600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace370000000067d1c81700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace380000000067d1c81800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace390000000067d1c81900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800004000000000000006ace3a0000000067d1c81b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3b0000000067d1c81c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3c0000000067d1c81d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3d0000000067d1c81f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace3e0000000067d1c82100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace3f0000000067d1c82300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace400000000067d1c82400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace410000000067d1c82500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace420000000067d1c82600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace430000000067d1c82700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace440000000067d1c82800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace450000000067d1c82900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace460000000067d1c82a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace470000000067d1c82b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace480000000067d1c82c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace490000000067d1c82d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace4a0000000067d1c82e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace4b0000000067d1c83000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4c0000000067d1c83100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4d0000000067d1c83200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace4e0000000067d1c83400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace4f0000000067d1c83500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace500000000067d1c83600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace510000000067d1c83700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace520000000067d1c83800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace530000000067d1c83900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace540000000067d1c83a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace550000000067d1c83b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace560000000067d1c83c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace570000000067d1c83d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace580000000067d1c83e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace590000000067d1c83f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5a0000000067d1c84100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5b0000000067d1c84200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5c0000000067d1c84300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5d0000000067d1c84400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace5e0000000067d1c84500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace5f0000000067d1c84700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace600000000067d1c84900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace610000000067d1c84a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace620000000067d1c84b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace630000000067d1c84c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace640000000067d1c84d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace650000000067d1c84e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace660000000067d1c84f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace670000000067d1c85000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace680000000067d1c85100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace690000000067d1c85200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6a0000000067d1c85300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace6b0000000067d1c85400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace6c0000000067d1c85600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6d0000000067d1c85800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace6e0000000067d1c85900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace6f0000000067d1c85a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace700000000067d1c85b00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace710000000067d1c85c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace720000000067d1c85d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace730000000067d1c85e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace740000000067d1c85f00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace750000000067d1c86000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace760000000067d1c86100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace770000000067d1c86300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace780000000067d1c86400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace790000000067d1c86500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7a0000000067d1c86700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7b0000000067d1c86800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7c0000000067d1c86900000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace7d0000000067d1c86a00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7e0000000067d1c86c00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace7f0000000067d1c86d00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace800000000067d1c86e00000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace810000000067d1c87000000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace820000000067d1c87100000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace830000000067d1c87200000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800003000000000000006ace840000000067d1c87300000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace850000000067d1c87400000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace860000000067d1c87500000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace870000000067d1c87600000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800002000000000000006ace880000000067d1c87700000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000006ace890000000067d1c87800000000000000000000000000000000000000000000000000000000000f42400000000001c9c3800001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000070000000000000000000000006ab0e960911b50f6d14f249782ac12ec3e7584a0000000000000000000000000bba36cdf020788f0d08d5688c0bee3fb30ce1c8000000000000000000000000034e387b37d3adeaa6d5b92ce30de3af3dca39796000000000000000000000000a59b26db10c5ca26a97aa2fd2e74cb8da9d1eb65000000000000000000000000f834ffbeb6bb3f4841afc6b5fb40b94cd580fa2300000000000000000000000061f2945d4bc9e40b66a6376d1094a50438f613e2000000000000000000000000b6cf39ee72e0127e6ea6059e38b8c197227a6ac700000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000015f903b2fe6b812c9c5b4882525df682e2a26238bdd18badf5a4d3bf2dc2ec8acd600d92182181e25359a631da62585b00000000000000000000000000000000022a08b55fac8d2669fb3a47977ac43b2b9918d953532cab1625c9e94f49c333b7160442a38e8399a285646df4081c60" bs, err := hex.DecodeString(calldata) require.NoError(t, err) - require.Zero(t, ParseParentBatchIndex(bs)) + require.EqualValues(t, ParseParentBatchIndex(bs), 14203) } func TestParseFBatchIndex(t *testing.T) { From f58020ff3d5657ab12e4dc89ac2bfa5b5b11ce8c Mon Sep 17 00:00:00 2001 From: Segue Date: Tue, 11 Aug 2026 19:29:59 +0800 Subject: [PATCH 18/38] chore(abi): freeze pre-submitters cutover baselines --- contracts/abi/archive/README.md | 12 + .../archive/legacy-l1-staking/L1Staking.json | 1033 ++++++++++++ contracts/abi/archive/manifest.json | 13 + .../abi/archive/pre-submitter/Rollup.json | 1416 +++++++++++++++++ .../archive/Rollup.pre-submitter.json | 424 +++++ .../app/src/abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ node/types/abi/pre_submitter_rollup.json | 1416 +++++++++++++++++ .../src/abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ .../abi/pre_submitter/Rollup.json | 1416 +++++++++++++++++ 9 files changed, 8562 insertions(+) create mode 100644 contracts/abi/archive/README.md create mode 100644 contracts/abi/archive/legacy-l1-staking/L1Staking.json create mode 100644 contracts/abi/archive/manifest.json create mode 100644 contracts/abi/archive/pre-submitter/Rollup.json create mode 100644 contracts/storage-layout/archive/Rollup.pre-submitter.json create mode 100644 gas-oracle/app/src/abi/pre_submitter/Rollup.json create mode 100644 node/types/abi/pre_submitter_rollup.json create mode 100644 prover/bin/challenge/src/abi/pre_submitter/Rollup.json create mode 100644 prover/bin/shadow-prove/abi/pre_submitter/Rollup.json diff --git a/contracts/abi/archive/README.md b/contracts/abi/archive/README.md new file mode 100644 index 000000000..20b3253a3 --- /dev/null +++ b/contracts/abi/archive/README.md @@ -0,0 +1,12 @@ +# Archived production ABIs + +These ABI-only artifacts are immutable compatibility inputs for the centralized +submitter cutover. They were frozen from the pre-Submitter source tree before +the current Rollup ABI was regenerated. + +- `pre-submitter/Rollup.json` decodes the three production submission methods + that still include `BatchSignatureInput`. +- `legacy-l1-staking/L1Staking.json` is the only runtime interface used by the + L1 staking retirement tooling after the legacy Solidity source is removed. + +Do not regenerate or overwrite these files from the current contracts. diff --git a/contracts/abi/archive/legacy-l1-staking/L1Staking.json b/contracts/abi/archive/legacy-l1-staking/L1Staking.json new file mode 100644 index 000000000..e8d86b6d8 --- /dev/null +++ b/contracts/abi/archive/legacy-l1-staking/L1Staking.json @@ -0,0 +1,1033 @@ +[ + { + "inputs": [ + { + "internalType": "address payable", + "name": "_messenger", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldChallengeDeposit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newChallengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeDepositUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGasLimit", + "type": "uint256" + } + ], + "name": "GasLimitAddStakerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldGasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newGasLimit", + "type": "uint256" + } + ], + "name": "GasLimitRemoveStakersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "name": "Registered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercentage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercentage", + "type": "uint256" + } + ], + "name": "RewardPercentageUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SlashRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "Slashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "stakers", + "type": "address[]" + } + ], + "name": "StakersRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldStakingValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newStakingValue", + "type": "uint256" + } + ], + "name": "StakingValueUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "add", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "remove", + "type": "address[]" + } + ], + "name": "WhitelistUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "unlockHeight", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [], + "name": "MESSENGER", + "outputs": [ + { + "internalType": "contract ICrossDomainMessenger", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OTHER_STAKING", + "outputs": [ + { + "internalType": "contract Staking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "blsPubkey", + "type": "bytes" + } + ], + "name": "blsKeys", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "challengeDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimSlashRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cleanStakerStore", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "deleteList", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "deleteableHeight", + "outputs": [ + { + "internalType": "uint256", + "name": "height", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasLimitAddStaker", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasLimitRemoveStakers", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getActiveStakers", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_staker", + "type": "address" + } + ], + "name": "getStakerBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getStakers", + "outputs": [ + { + "internalType": "address[255]", + "name": "", + "type": "address[255]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_stakers", + "type": "address[]" + } + ], + "name": "getStakersBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "bitmap", + "type": "uint256" + } + ], + "name": "getStakersFromBitmap", + "outputs": [ + { + "internalType": "address[]", + "name": "stakerAddrs", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rollupContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_stakingValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_lockBlocks", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_rewardPercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimitAdd", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_gasLimitRemove", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isActiveStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isStaker", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isStakerInDeleteList", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messenger", + "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": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "name": "register", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_stakers", + "type": "address[]" + } + ], + "name": "removeStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "removedList", + "outputs": [ + { + "internalType": "bool", + "name": "removed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sequencersBitmap", + "type": "uint256" + } + ], + "name": "slash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "stakerIndexes", + "outputs": [ + { + "internalType": "uint8", + "name": "index", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "stakerSet", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "stakers", + "outputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "tmKey", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "blsKey", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakingValue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "tmPubkey", + "type": "bytes32" + } + ], + "name": "tmKeys", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_challengeDeposit", + "type": "uint256" + } + ], + "name": "updateChallengeDeposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasLimitAdd", + "type": "uint256" + } + ], + "name": "updateGasLimitAddStaker", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasLimitRemove", + "type": "uint256" + } + ], + "name": "updateGasLimitRemoveStakers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rewardPercentage", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_stakingValue", + "type": "uint256" + } + ], + "name": "updateStakingValue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "add", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "remove", + "type": "address[]" + } + ], + "name": "updateWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "", + "type": "address[]" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "verifySignature", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakerAddr", + "type": "address" + } + ], + "name": "whitelist", + "outputs": [ + { + "internalType": "bool", + "name": "inWhitelist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawalLockBlocks", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "withdrawals", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/contracts/abi/archive/manifest.json b/contracts/abi/archive/manifest.json new file mode 100644 index 000000000..fd4d36083 --- /dev/null +++ b/contracts/abi/archive/manifest.json @@ -0,0 +1,13 @@ +{ + "sourceCommit": "3d21e1f45f743b7fb4131fd6655ceb4d99f15356", + "artifacts": { + "pre-submitter/Rollup.json": "aea8c9f75f2c8e132a4ffca3f0bb3f6abd83ae2ae9457827a099e75463c5c03a", + "legacy-l1-staking/L1Staking.json": "df14c1e4264ba93661b1476ed9166ab06e03d077713fa13b16fded7f1dd6eb46", + "../../storage-layout/archive/Rollup.pre-submitter.json": "f8a745e49d6ea6e141ae26440ce12d6b2feeb155ef1dfdbe9dff40d124c59c37" + }, + "selectors": { + "commitBatch": "0x428868b5", + "commitState": "0x1e8825be", + "commitBatchWithProof": "0x4e8f1d67" + } +} diff --git a/contracts/abi/archive/pre-submitter/Rollup.json b/contracts/abi/archive/pre-submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/contracts/abi/archive/pre-submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/contracts/storage-layout/archive/Rollup.pre-submitter.json b/contracts/storage-layout/archive/Rollup.pre-submitter.json new file mode 100644 index 000000000..847c1cf90 --- /dev/null +++ b/contracts/storage-layout/archive/Rollup.pre-submitter.json @@ -0,0 +1,424 @@ +{ + "storage": [ + { + "astId": 123005, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 123008, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 125558, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 122758, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 122878, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 123189, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "_paused", + "offset": 0, + "slot": "101", + "type": "t_bool" + }, + { + "astId": 123294, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 8103, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "l1StakingContract", + "offset": 0, + "slot": "151", + "type": "t_address" + }, + { + "astId": 8106, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizationPeriodSeconds", + "offset": 0, + "slot": "152", + "type": "t_uint256" + }, + { + "astId": 8109, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proofWindow", + "offset": 0, + "slot": "153", + "type": "t_uint256" + }, + { + "astId": 8112, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "__maxNumTxInChunk", + "offset": 0, + "slot": "154", + "type": "t_uint256" + }, + { + "astId": 8115, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "messageQueue", + "offset": 0, + "slot": "155", + "type": "t_address" + }, + { + "astId": 8118, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "verifier", + "offset": 0, + "slot": "156", + "type": "t_address" + }, + { + "astId": 8122, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "lastFinalizedBatchIndex", + "offset": 0, + "slot": "157", + "type": "t_uint256" + }, + { + "astId": 8126, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "lastCommittedBatchIndex", + "offset": 0, + "slot": "158", + "type": "t_uint256" + }, + { + "astId": 8131, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "isChallenger", + "offset": 0, + "slot": "159", + "type": "t_mapping(t_address,t_bool)" + }, + { + "astId": 8137, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizedStateRoots", + "offset": 0, + "slot": "160", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8143, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "committedBatches", + "offset": 0, + "slot": "161", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8149, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchDataStore", + "offset": 0, + "slot": "162", + "type": "t_mapping(t_uint256,t_struct(BatchData)6917_storage)" + }, + { + "astId": 8154, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "withdrawalRoots", + "offset": 0, + "slot": "163", + "type": "t_mapping(t_bytes32,t_bool)" + }, + { + "astId": 8160, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challenges", + "offset": 0, + "slot": "164", + "type": "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)" + }, + { + "astId": 8165, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchChallengeReward", + "offset": 0, + "slot": "165", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 8168, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "inChallenge", + "offset": 0, + "slot": "166", + "type": "t_bool" + }, + { + "astId": 8171, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchChallenged", + "offset": 0, + "slot": "167", + "type": "t_uint256" + }, + { + "astId": 8174, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "revertReqIndex", + "offset": 0, + "slot": "168", + "type": "t_uint256" + }, + { + "astId": 8177, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proofRewardPercent", + "offset": 0, + "slot": "169", + "type": "t_uint256" + }, + { + "astId": 8180, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "proveRemaining", + "offset": 0, + "slot": "170", + "type": "t_uint256" + }, + { + "astId": 8185, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "committedStateRoots", + "offset": 0, + "slot": "171", + "type": "t_mapping(t_uint256,t_bytes32)" + }, + { + "astId": 8188, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "rollupDelayPeriod", + "offset": 0, + "slot": "172", + "type": "t_uint256" + }, + { + "astId": 8193, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchBlobVersionedHashes", + "offset": 0, + "slot": "173", + "type": "t_mapping(t_uint256,t_bytes32)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568", + "base": "t_uint256" + }, + "t_array(t_uint256)50_storage": { + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600", + "base": "t_uint256" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_bytes32,t_bool)": { + "encoding": "mapping", + "key": "t_bytes32", + "label": "mapping(bytes32 => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_bytes32)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => bytes32)", + "numberOfBytes": "32", + "value": "t_bytes32" + }, + "t_mapping(t_uint256,t_struct(BatchChallenge)6931_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct IRollup.BatchChallenge)", + "numberOfBytes": "32", + "value": "t_struct(BatchChallenge)6931_storage" + }, + "t_mapping(t_uint256,t_struct(BatchData)6917_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct IRollup.BatchData)", + "numberOfBytes": "32", + "value": "t_struct(BatchData)6917_storage" + }, + "t_struct(BatchChallenge)6931_storage": { + "encoding": "inplace", + "label": "struct IRollup.BatchChallenge", + "numberOfBytes": "128", + "members": [ + { + "astId": 6920, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "batchIndex", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 6922, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challenger", + "offset": 8, + "slot": "0", + "type": "t_address" + }, + { + "astId": 6924, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challengeDeposit", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 6926, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "startTime", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 6928, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "challengeSuccess", + "offset": 0, + "slot": "3", + "type": "t_bool" + }, + { + "astId": 6930, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finished", + "offset": 1, + "slot": "3", + "type": "t_bool" + } + ] + }, + "t_struct(BatchData)6917_storage": { + "encoding": "inplace", + "label": "struct IRollup.BatchData", + "numberOfBytes": "128", + "members": [ + { + "astId": 6910, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "originTimestamp", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 6912, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "finalizeTimestamp", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 6914, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "blockNumber", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 6916, + "contract": "contracts/l1/rollup/Rollup.sol:Rollup", + "label": "signedSequencersBitmap", + "offset": 0, + "slot": "3", + "type": "t_uint256" + } + ] + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint64": { + "encoding": "inplace", + "label": "uint64", + "numberOfBytes": "8" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } +} diff --git a/gas-oracle/app/src/abi/pre_submitter/Rollup.json b/gas-oracle/app/src/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/gas-oracle/app/src/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/node/types/abi/pre_submitter_rollup.json b/node/types/abi/pre_submitter_rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/node/types/abi/pre_submitter_rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json new file mode 100644 index 000000000..c8c7586c1 --- /dev/null +++ b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json @@ -0,0 +1,1416 @@ +[ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainID", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ErrZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": true, + "internalType": "string", + "name": "res", + "type": "string" + } + ], + "name": "ChallengeRes", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ChallengeRewardClaim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + } + ], + "name": "ChallengeState", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "CommitBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawRoot", + "type": "bytes32" + } + ], + "name": "FinalizeBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProveRemainingClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "name": "RevertBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "UpdateChallenger", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateFinalizationPeriodSeconds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPercent", + "type": "uint256" + } + ], + "name": "UpdateProofRewardPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldWindow", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newWindow", + "type": "uint256" + } + ], + "name": "UpdateProofWindow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldVerifier", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newVerifier", + "type": "address" + } + ], + "name": "UpdateVerifier", + "type": "event" + }, + { + "inputs": [], + "name": "LAYER_2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "__maxNumTxInChunk", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "batchChallengeReward", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batchChallenged", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchChallengedSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchDataStore", + "outputs": [ + { + "internalType": "uint256", + "name": "originTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "finalizeTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchExist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchInsideChallengeWindow", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batchHash", + "type": "bytes32" + } + ], + "name": "challengeState", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "challenges", + "outputs": [ + { + "internalType": "uint64", + "name": "batchIndex", + "type": "uint64" + }, + { + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "internalType": "uint256", + "name": "challengeDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "challengeSuccess", + "type": "bool" + }, + { + "internalType": "bool", + "name": "finished", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimProveRemaining", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "parentBatchHeader", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" + } + ], + "name": "commitState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedBatches", + "outputs": [ + { + "internalType": "bytes32", + "name": "batchHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "committedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finalizationPeriodSeconds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "finalizeBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "finalizedStateRoots", + "outputs": [ + { + "internalType": "bytes32", + "name": "stateRoot", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + } + ], + "name": "importGenesisBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "inChallenge", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_l1StakingContract", + "type": "address" + }, + { + "internalType": "address", + "name": "_messageQueue", + "type": "address" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_finalizationPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofWindow", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_proofRewardPercent", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_prevStateRoot", + "type": "bytes32" + } + ], + "name": "initialize2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "name": "isBatchFinalized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "challengerAddress", + "type": "address" + } + ], + "name": "isChallenger", + "outputs": [ + { + "internalType": "bool", + "name": "isChallenger", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastCommittedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFinalizedBatchIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageQueue", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofRewardPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofWindow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proveRemaining", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeChallenger", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "revertBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revertReqIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setPause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateFinalizePeriodSeconds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newWindow", + "type": "uint256" + } + ], + "name": "updateProofWindow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newProofRewardPercent", + "type": "uint256" + } + ], + "name": "updateRewardPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newVerifier", + "type": "address" + } + ], + "name": "updateVerifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "name": "withdrawalRoots", + "outputs": [ + { + "internalType": "bool", + "name": "exist", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] From e6ab2de580d24b06ce023b22ed0589c28755b560 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 05:47:50 +0800 Subject: [PATCH 19/38] feat(contracts): introduce staked batch submitters --- contracts/contracts/Staking.md | 134 -- contracts/contracts/l1/rollup/BLS.sol | 4 - contracts/contracts/l1/rollup/IRollup.sol | 36 +- contracts/contracts/l1/rollup/ISubmitter.sol | 18 + contracts/contracts/l1/rollup/Rollup.sol | 131 +- contracts/contracts/l1/rollup/Submitter.sol | 181 +++ contracts/contracts/l1/staking/IL1Staking.sol | 119 -- contracts/contracts/l1/staking/L1Staking.sol | 515 -------- contracts/contracts/test/L1Staking.t.sol | 1154 ----------------- contracts/contracts/test/Rollup.t.sol | 394 +++--- contracts/contracts/test/Submitter.t.sol | 207 +++ .../contracts/test/base/L1MessageBase.t.sol | 43 +- 12 files changed, 694 insertions(+), 2242 deletions(-) delete mode 100644 contracts/contracts/Staking.md delete mode 100644 contracts/contracts/l1/rollup/BLS.sol create mode 100644 contracts/contracts/l1/rollup/ISubmitter.sol create mode 100644 contracts/contracts/l1/rollup/Submitter.sol delete mode 100644 contracts/contracts/l1/staking/IL1Staking.sol delete mode 100644 contracts/contracts/l1/staking/L1Staking.sol delete mode 100644 contracts/contracts/test/L1Staking.t.sol create mode 100644 contracts/contracts/test/Submitter.t.sol diff --git a/contracts/contracts/Staking.md b/contracts/contracts/Staking.md deleted file mode 100644 index b657c8114..000000000 --- a/contracts/contracts/Staking.md +++ /dev/null @@ -1,134 +0,0 @@ -# Staking - ---- - -## Core Process - -**Staking & Sequencer Selection** - -Morph token staking will be divided into three stages: - -- MorphToken has not yet issued yet -- MorphToken has been issued, but inflation and staking rewards have not started yet. -- Inflation starts and distribute staking rewards - -1. `L1` Update whitelist -2. `L1` Register and stake eth to become staker -3. `L1->L2` Send {add staker} message -4. `L2` Update stakers -5. `L2` Delegate stake MorphToken to staker -6. `L2` Update sequencer set by amount of MorphToken delegation - -**Rollp Verify** - -- The submitted batch requires the BLS signature of more than 2/3 of the sequencers -- Before BLS implementation, only staker (not withdrawing, not slashing) can rollup - -1. `L1` Submit batch and sequencer sets -2. `L1` Verify sequencer set -3. `L1` Verify batch signature - -**Slash Sequencers After Challenger Win** - -- Sequencer will be confiscated all stake amount and removed from sequencer set if defense challenge fails -- Even if challenged repeatedly, each sequencer will only be slashed once -- The reward for a successful challenge is a fixed proportion of the staking amount, and is greater than the challenge deposit -- If the slash causes the number of sequences to be 0, then the layer2 will stop running. We can restart by upgrading, reset stakers and sequencer set. This does not affect the security of the evm state - -1. `L1` Slash staking value of signed sequencers and remove from stakers -2. `L1` Distribute challenger rewards -3. `L1->L2` Send {remove stakers} message -4. `L2` Update sequencer set by amount of MorphToken delegation - -**Delegation Rewards** - -- MorphToken is inflated at a fixed ratio every day, and the additional tokens are used as rewards for sequencers and delegators -- The sequencer and his delegators get MorphToken inflation reward according to the block production ratio -- Sequencer charges commission as its own income -- Users get remaining reward according to their delegation amount - -1. `L2` Staker set delegation commission rate -2. `L2` Upload sequencers work records in epoch (an epoch is a day) -3. `L2` Mint MorphToken inflation as delegation reward -4. `L2` Claim delegation reward or claim commission - -**Quit Staker** - -The exit lock period should be long enough to ensure that stakers and sequencers in L2 have been updated - -1. `L1` Apply to withdraw, remove from staker list, enter lock period -2. `L1->L2` Send {remove staker} message -3. `L2` Remove from stakers and sequencers if needed -4. `L1` Claim allowed until reach unlock height,remove staker info after claiming - ---- - -## Contracts - -### L1 Contract - -#### L1Staking Contract - -**Main functions** - -- Update whitelist -- Register as staker -- Staker quit -- Slash signed sequencers if challenger win, call by rollup contract - -#### Rollup Contract - -**Main functions** - -- Commit batch & verify -- Challenge batch - -### L2 Contract - -#### MorphToken Contract - -**Main functions** - -- Mint inflation - -#### Record Contract - -**Main functions** - -- Record finalized batch submissions, call by oracle -- Record rollup epochs, call by oracle -- Record reward epochs, call by oracle - -#### L2Staking Contract - -**Main functions** - -- Add staker, sync from L1 staking contract -- Remove stakers, sync from L1 staking contract -- Staker set commission rate -- User delegate stake morph token -- User undelegate stake morph token -- User claim delegation reward -- Sequencer claim commission - -#### Sequencer Contract - -**Main functions** - -- Update sequencer set, call form l2 staking contract - -#### Distribute Contract - -**Main functions** - -- Record delegation info by l2 staking contract -- Record undelegation info by l2 staking contract -- Compute delegator's delegation reward, call form l2 staking contract -- Compute sequencer's commission, call form l2 staking contract - -#### Gov Contract - -**Main functions** - -- Submit proposal -- Vote proposal diff --git a/contracts/contracts/l1/rollup/BLS.sol b/contracts/contracts/l1/rollup/BLS.sol deleted file mode 100644 index 5f78c7036..000000000 --- a/contracts/contracts/l1/rollup/BLS.sol +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -contract BLS {} diff --git a/contracts/contracts/l1/rollup/IRollup.sol b/contracts/contracts/l1/rollup/IRollup.sol index d6691cb14..bbaa21201 100644 --- a/contracts/contracts/l1/rollup/IRollup.sol +++ b/contracts/contracts/l1/rollup/IRollup.sol @@ -23,23 +23,15 @@ interface IRollup { bytes32 withdrawalRoot; } - /// @param signedSequencers The bitmap of signed sequencers - /// @param sequencerSets The latest 3 sequencer sets - /// @param signature The BLS signature - struct BatchSignatureInput { - uint256 signedSequencersBitmap; - bytes sequencerSets; - bytes signature; - } - /// @param originTimestamp /// @param finalizeTimestamp /// @param blockNumber + /// @param submitter The account responsible for the batch, or zero for permissionless submissions. struct BatchData { uint256 originTimestamp; uint256 finalizeTimestamp; uint256 blockNumber; - uint256 signedSequencersBitmap; + address submitter; } /// @dev Structure to store information about a batch challenge. @@ -128,6 +120,9 @@ interface IRollup { /// @param amount claimed amount. event ProveRemainingClaimed(address receiver, uint256 amount); + /// @notice Emitted when the legacy staking dependency is replaced with Submitter. + event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr); + /// @notice Emitted when the state of Challenge is updated. /// @param batchIndex The index of the batch. /// @param challenger The address of challenger. @@ -180,30 +175,21 @@ interface IRollup { /// @notice Commit a batch of transactions on layer 1. /// - /// @param batchDataInput The BatchDataInput struct - /// @param batchSignatureInput The BatchSignatureInput struct - function commitBatch( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external payable; + /// @param batchDataInput The BatchDataInput struct + function commitBatch(BatchDataInput calldata batchDataInput) external payable; /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). /// @dev Requires batchBlobVersionedHashes[nextBatchIndex] != 0. - function commitState( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external; + function commitState(BatchDataInput calldata batchDataInput) external; /// @notice Commit a batch with ZKP proof for permissionless submission. /// @dev This function allows anyone to submit batches when the sequencer is offline or censoring. /// - /// @param batchDataInput The BatchDataInput struct - /// @param batchSignatureInput The BatchSignatureInput struct - /// @param batchHeader The batch header for ZKP verification - /// @param batchProof The ZKP proof data + /// @param batchDataInput The BatchDataInput struct + /// @param batchHeader The batch header for ZKP verification + /// @param batchProof The ZKP proof data function commitBatchWithProof( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, bytes calldata batchHeader, bytes calldata batchProof ) external; diff --git a/contracts/contracts/l1/rollup/ISubmitter.sol b/contracts/contracts/l1/rollup/ISubmitter.sol new file mode 100644 index 000000000..63e540b89 --- /dev/null +++ b/contracts/contracts/l1/rollup/ISubmitter.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +/// @notice Interface used by Rollup to authorize and slash batch submitters. +interface ISubmitter { + function isActive(address submitter) external view returns (bool); + + function challengeDeposit() external view returns (uint256); + + function slash(address submitter) external returns (uint256 reward); +} + +/// @notice Existing Rollup state used to release all submitter stake after a global drain. +interface IRollupSubmitterView { + function lastCommittedBatchIndex() external view returns (uint256); + + function lastFinalizedBatchIndex() external view returns (uint256); +} diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 14aae181b..2822701b3 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -9,7 +9,7 @@ import {BatchHeaderCodecV1} from "../../libraries/codec/BatchHeaderCodecV1.sol"; import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol"; import {IL1MessageQueue} from "./IL1MessageQueue.sol"; import {IRollup} from "./IRollup.sol"; -import {IL1Staking} from "../staking/IL1Staking.sol"; +import {ISubmitter} from "./ISubmitter.sol"; // solhint-disable no-inline-assembly // solhint-disable reason-string @@ -24,13 +24,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice The zero versioned hash. bytes32 internal constant ZERO_VERSIONED_HASH = 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014; - /// @notice The BLS MODULUS. Deprecated. - uint256 internal constant __BLS_MODULUS = - 52435875175126190479447740508185965837690552500527637822603658699938581184513; - - /// @dev Address of the point evaluation precompile used for EIP-4844 blob verification. - address internal constant POINT_EVALUATION_PRECOMPILE_ADDR = address(0x0A); - /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable LAYER_2_CHAIN_ID; @@ -38,8 +31,9 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { * Variables * *************/ - /// @notice L1 staking contract - address public l1StakingContract; + /// @notice Submitter registration and staking contract. + /// @dev Occupies the legacy staking dependency's storage slot. + address public submitterContract; /// @notice Batch challenge time. uint256 public finalizationPeriodSeconds; @@ -113,9 +107,9 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { * Function Modifiers * **********************/ - /// @notice Only active staker allowed. - modifier onlyActiveStaker() { - require(IL1Staking(l1StakingContract).isActiveStaker(_msgSender()), "only active staker allowed"); + /// @notice Only an active submitter is allowed. + modifier onlyActiveSubmitter() { + require(ISubmitter(submitterContract).isActive(_msgSender()), "only active submitter allowed"); _; } @@ -150,13 +144,13 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ***************/ /// @notice initializer - /// @param _l1StakingContract l1 staking contract + /// @param _submitterContract submitter contract /// @param _messageQueue message queue /// @param _verifier verifier /// @param _finalizationPeriodSeconds finalization period seconds /// @param _proofWindow proof window function initialize( - address _l1StakingContract, + address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, @@ -166,12 +160,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (_messageQueue == address(0) || _verifier == address(0)) { revert ErrZeroAddress(); } - require(_l1StakingContract != address(0), "invalid l1 staking contract"); + require(_submitterContract != address(0), "invalid submitter contract"); __Pausable_init(); __Ownable_init(); - l1StakingContract = _l1StakingContract; + submitterContract = _submitterContract; messageQueue = _messageQueue; verifier = _verifier; finalizationPeriodSeconds = _finalizationPeriodSeconds; @@ -200,6 +194,18 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { emit UpdateRollupDelayPeriod(0, _rollupDelayPeriod); } + /// @notice One-time cutover from the legacy staking address to the Submitter proxy. + /// @dev Called atomically through the existing ProxyAdmin upgradeAndCall flow. + function initialize4(address _newSubmitter) external reinitializer(4) { + require(_newSubmitter != address(0) && _newSubmitter.code.length > 0, "invalid submitter"); + require(lastCommittedBatchIndex == lastFinalizedBatchIndex, "pending batches"); + require(!inChallenge, "challenge in progress"); + require(revertReqIndex == 0, "pending revert request"); + + emit SubmitterContractUpdated(submitterContract, _newSubmitter); + submitterContract = _newSubmitter; + } + /************************ * Restricted Functions * ************************/ @@ -221,7 +227,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { require(BatchHeaderCodecV0.getBlobVersionedHash(memPtr) == ZERO_VERSIONED_HASH, "invalid versioned hash"); committedBatches[_batchIndex] = _batchHash; - batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, 0); + batchDataStore[_batchIndex] = BatchData(block.timestamp, block.timestamp, 0, address(0)); batchBlobVersionedHashes[_batchIndex] = BatchHeaderCodecV0.getBlobVersionedHash(memPtr); committedStateRoots[_batchIndex] = _postStateRoot; @@ -235,9 +241,8 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @inheritdoc IRollup function commitBatch( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external payable override onlyActiveStaker nonReqRevert whenNotPaused { + BatchDataInput calldata batchDataInput + ) external payable override onlyActiveSubmitter nonReqRevert whenNotPaused { // check if the next batch has a stored blob hash (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; @@ -247,17 +252,15 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); bytes32 _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); - _commitBatchWithBatchData(batchDataInput, batchSignatureInput, submitterBitmap, _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, _msgSender(), _blobVersionedHash); } /// @inheritdoc IRollup /// @notice Commit batch state when blob hash is already stored (recommit after revert without blob). function commitState( - BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput - ) external override onlyActiveStaker nonReqRevert whenNotPaused { + BatchDataInput calldata batchDataInput + ) external override onlyActiveSubmitter nonReqRevert whenNotPaused { require(blobhash(0) == bytes32(0), "commitState must not carry blob"); (uint256 _batchPtr, ) = _loadBatchHeader(batchDataInput.parentBatchHeader); uint256 _nextBatchIndex = BatchHeaderCodecV0.getBatchIndex(_batchPtr) + 1; @@ -267,19 +270,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); - _commitBatchWithBatchData( - batchDataInput, - batchSignatureInput, - submitterBitmap, - batchBlobVersionedHashes[_nextBatchIndex] - ); + _commitBatchWithBatchData(batchDataInput, _msgSender(), batchBlobVersionedHashes[_nextBatchIndex]); } function _commitBatchWithBatchData( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, - uint256 submitterBitmap, + address submitter, bytes32 blobVersionedHash ) internal { require(batchDataInput.version <= 2, "invalid version"); @@ -340,10 +336,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { BatchHeaderCodecV0.storePrevStateHash(_batchPtr, batchDataInput.prevStateRoot); BatchHeaderCodecV0.storePostStateHash(_batchPtr, batchDataInput.postStateRoot); BatchHeaderCodecV0.storeWithdrawRootHash(_batchPtr, batchDataInput.withdrawalRoot); - BatchHeaderCodecV0.storeSequencerSetVerifyHash( - _batchPtr, - keccak256(batchSignatureInput.sequencerSets) - ); + BatchHeaderCodecV0.storeSequencerSetVerifyHash(_batchPtr, bytes32(0)); BatchHeaderCodecV0.storeParentBatchHash(_batchPtr, _parentBatchHash); if (batchDataInput.version >= 1) { BatchHeaderCodecV1.storeLastBlockNumber(_batchPtr, batchDataInput.lastBlockNumber); @@ -362,24 +355,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { block.timestamp, block.timestamp + finalizationPeriodSeconds + proveRemainingTime, batchDataInput.lastBlockNumber, - // Before BLS is implemented, the accuracy of the sequencer set uploaded by rollup cannot be guaranteed. - // Therefore, if the batch is successfully challenged, only the submitter will be punished. - submitterBitmap // => batchSignature.signedSequencersBitmap + submitter ); lastCommittedBatchIndex = _batchIndex; } - // verify bls signature - require( - IL1Staking(l1StakingContract).verifySignature( - batchSignatureInput.signedSequencersBitmap, - _getValidSequencerSet(batchSignatureInput.sequencerSets, 0), - _getBLSMsgHash(batchDataInput), - batchSignatureInput.signature - ), - "the signature verification failed" - ); emit CommitBatch(_batchIndex, committedBatches[_batchIndex]); } @@ -388,7 +369,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// Entry conditions: rollup delay OR L1 message queue delay must be met. function commitBatchWithProof( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput, bytes calldata _batchHeader, bytes calldata _batchProof ) external override nonReqRevert whenNotPaused { @@ -416,7 +396,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { } else { _blobVersionedHash = _computeBlobVersionedHash(batchDataInput.version); } - _commitBatchWithBatchData(batchDataInput, batchSignatureInput, 0, _blobVersionedHash); + _commitBatchWithBatchData(batchDataInput, address(0), _blobVersionedHash); // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); @@ -488,7 +468,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { // check challenge window require(batchInsideChallengeWindow(batchIndex), "cannot challenge batch outside the challenge window"); // check challenge amount - require(msg.value >= IL1Staking(l1StakingContract).challengeDeposit(), "insufficient value"); + require(msg.value >= ISubmitter(submitterContract).challengeDeposit(), "insufficient value"); batchChallenged = batchIndex; challenges[batchIndex] = BatchChallenge(batchIndex, _msgSender(), msg.value, block.timestamp, false, false); @@ -603,7 +583,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { function proveState( bytes calldata _batchHeader, bytes calldata _batchProof - ) external nonReqRevert whenNotPaused onlyActiveStaker { + ) external nonReqRevert whenNotPaused onlyActiveSubmitter { // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); // check batch hash @@ -621,7 +601,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { if (challenges[_batchIndex].startTime + proofWindow <= block.timestamp) { // set status challenges[_batchIndex].challengeSuccess = true; - _challengerWin(_batchIndex, batchDataStore[_batchIndex].signedSequencersBitmap, "Timeout"); + _challengerWin(_batchIndex, batchDataStore[_batchIndex].submitter, "Timeout"); } else { _verifyProof(memPtr, _batchProof); // Record defender win @@ -784,37 +764,6 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ); } - /// @dev Internal function to compute BLS msg hash - function _getBLSMsgHash( - BatchDataInput calldata // batchDataInput - ) internal pure returns (bytes32) { - // TODO compute bls message hash - return bytes32(0); - } - - /// @dev todo - function _getValidSequencerSet( - bytes calldata sequencerSets, - uint256 blockHeight - ) internal pure returns (address[] memory) { - // TODO require submitter was in valid sequencer set after BLS was implemented - ( - , - address[] memory sequencerSet0, - uint256 blockHeight1, - address[] memory sequencerSet1, - uint256 blockHeight2, - address[] memory sequencerSet2 - ) = abi.decode(sequencerSets, (uint256, address[], uint256, address[], uint256, address[])); - if (blockHeight >= blockHeight2) { - return sequencerSet2; - } - if (blockHeight >= blockHeight1) { - return sequencerSet1; - } - return sequencerSet0; - } - /// @dev Internal function executed when the defender wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. /// @param prover The zkProof prover address. @@ -829,12 +778,12 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Internal function executed when the challenger wins. /// @param batchIndex The index of the batch indicating where the challenge occurred. - /// @param sequencersBitmap An array containing the sequencers to be slashed. + /// @param submitter The submitter responsible for the challenged batch. /// @param _type Description of the challenge type. - function _challengerWin(uint256 batchIndex, uint256 sequencersBitmap, string memory _type) internal { + function _challengerWin(uint256 batchIndex, address submitter, string memory _type) internal { revertReqIndex = batchIndex; address challenger = challenges[batchIndex].challenger; - uint256 reward = IL1Staking(l1StakingContract).slash(sequencersBitmap); + uint256 reward = ISubmitter(submitterContract).slash(submitter); batchChallengeReward[challenges[batchIndex].challenger] += (challenges[batchIndex].challengeDeposit + reward); emit ChallengeRes(batchIndex, challenger, _type); } diff --git a/contracts/contracts/l1/rollup/Submitter.sol b/contracts/contracts/l1/rollup/Submitter.sol new file mode 100644 index 000000000..d2a9cd7ef --- /dev/null +++ b/contracts/contracts/l1/rollup/Submitter.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; + +import {IRollupSubmitterView, ISubmitter} from "./ISubmitter.sol"; + +/// @title Submitter +/// @notice Registration, stake, exit, and slashing for batch submitters. +contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable { + address public rollupContract; + uint256 public minimumStake; + uint256 public override challengeDeposit; + uint256 public rewardPercentage; + uint256 public slashRemaining; + + mapping(address submitter => bool isRegistered) public registered; + mapping(address submitter => uint256 amount) public stakeOf; + mapping(address submitter => bool isWithdrawing) public withdrawing; + + event SubmitterAdded(address indexed submitter); + event SubmitterRemoved(address indexed submitter); + event MinimumStakeUpdated(uint256 oldValue, uint256 newValue); + event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue); + event RewardPercentageUpdated(uint256 oldValue, uint256 newValue); + event Staked(address indexed submitter, uint256 amount, uint256 total); + event WithdrawalRequested(address indexed submitter, uint256 amount); + event WithdrawalClaimed(address indexed submitter, address indexed receiver, uint256 amount); + event Slashed(address indexed submitter, uint256 amount, uint256 reward); + event SlashRemainingClaimed(address indexed receiver, uint256 amount); + + modifier onlyRollup() { + require(_msgSender() == rollupContract, "only rollup contract"); + _; + } + + constructor() { + _disableInitializers(); + } + + function initialize( + address owner_, + address rollupContract_, + uint256 minimumStake_, + uint256 challengeDeposit_, + uint256 rewardPercentage_ + ) external initializer { + require(owner_ != address(0), "invalid owner"); + require(rollupContract_ != address(0) && rollupContract_.code.length > 0, "invalid rollup contract"); + require(minimumStake_ > 0, "invalid minimum stake"); + require(challengeDeposit_ > 0, "invalid challenge deposit"); + require(rewardPercentage_ > 0 && rewardPercentage_ <= 100, "invalid reward percentage"); + + __Ownable_init(); + __ReentrancyGuard_init(); + _transferOwnership(owner_); + + rollupContract = rollupContract_; + minimumStake = minimumStake_; + challengeDeposit = challengeDeposit_; + rewardPercentage = rewardPercentage_; + + emit MinimumStakeUpdated(0, minimumStake_); + emit ChallengeDepositUpdated(0, challengeDeposit_); + emit RewardPercentageUpdated(0, rewardPercentage_); + } + + function isActive(address submitter) public view override returns (bool) { + return registered[submitter] && !withdrawing[submitter] && stakeOf[submitter] >= minimumStake; + } + + function addSubmitter(address submitter) external onlyOwner { + require( + submitter != address(0) && + !registered[submitter] && + !withdrawing[submitter] && + stakeOf[submitter] == 0, + "invalid submitter" + ); + registered[submitter] = true; + emit SubmitterAdded(submitter); + } + + function removeSubmitter(address submitter) external onlyOwner { + require(registered[submitter] && !withdrawing[submitter], "invalid submitter"); + registered[submitter] = false; + uint256 amount = stakeOf[submitter]; + if (amount > 0) { + withdrawing[submitter] = true; + emit WithdrawalRequested(submitter, amount); + } + emit SubmitterRemoved(submitter); + } + + function setMinimumStake(uint256 value) external onlyOwner { + require(value > 0 && value != minimumStake, "invalid minimum stake"); + emit MinimumStakeUpdated(minimumStake, value); + minimumStake = value; + } + + function updateChallengeDeposit(uint256 value) external onlyOwner { + require(value > 0 && value != challengeDeposit, "invalid challenge deposit"); + emit ChallengeDepositUpdated(challengeDeposit, value); + challengeDeposit = value; + } + + function updateRewardPercentage(uint256 value) external onlyOwner { + require(value > 0 && value <= 100 && value != rewardPercentage, "invalid reward percentage"); + emit RewardPercentageUpdated(rewardPercentage, value); + rewardPercentage = value; + } + + function stake() external payable nonReentrant { + address submitter = _msgSender(); + require(registered[submitter] && !withdrawing[submitter], "not stakeable"); + uint256 total = stakeOf[submitter] + msg.value; + require(msg.value > 0 && total >= minimumStake, "below minimum stake"); + stakeOf[submitter] = total; + emit Staked(submitter, msg.value, total); + } + + function withdraw() external { + address submitter = _msgSender(); + require(registered[submitter] && !withdrawing[submitter] && stakeOf[submitter] > 0, "not withdrawable"); + + // Exiting always revokes the owner's previous authorization. Re-entry requires addSubmitter. + registered[submitter] = false; + withdrawing[submitter] = true; + emit WithdrawalRequested(submitter, stakeOf[submitter]); + } + + function claimWithdrawal(address receiver) external nonReentrant { + address submitter = _msgSender(); + require(receiver != address(0), "invalid receiver"); + require(withdrawing[submitter], "not withdrawing"); + require(_isGloballyDrained(), "rollup not drained"); + + uint256 amount = stakeOf[submitter]; + stakeOf[submitter] = 0; + withdrawing[submitter] = false; + _transfer(receiver, amount); + emit WithdrawalClaimed(submitter, receiver, amount); + } + + function slash(address submitter) external override onlyRollup nonReentrant returns (uint256 reward) { + if (submitter == address(0)) return 0; + + uint256 amount = stakeOf[submitter]; + registered[submitter] = false; + stakeOf[submitter] = 0; + withdrawing[submitter] = false; + + reward = (amount * rewardPercentage) / 100; + slashRemaining += amount - reward; + _transfer(rollupContract, reward); + emit Slashed(submitter, amount, reward); + } + + function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { + require(receiver != address(0), "invalid receiver"); + uint256 amount = slashRemaining; + require(amount > 0, "no slash remaining"); + slashRemaining = 0; + _transfer(receiver, amount); + emit SlashRemainingClaimed(receiver, amount); + } + + function _isGloballyDrained() internal view returns (bool) { + IRollupSubmitterView rollup = IRollupSubmitterView(rollupContract); + return rollup.lastCommittedBatchIndex() == rollup.lastFinalizedBatchIndex(); + } + + function _transfer(address receiver, uint256 amount) internal { + if (amount == 0) return; + (bool success, ) = receiver.call{value: amount}(""); + require(success, "ETH transfer failed"); + } + + uint256[50] private __gap; +} diff --git a/contracts/contracts/l1/staking/IL1Staking.sol b/contracts/contracts/l1/staking/IL1Staking.sol deleted file mode 100644 index ba4f6801b..000000000 --- a/contracts/contracts/l1/staking/IL1Staking.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -interface IL1Staking { - /********** - * Events * - **********/ - - /// @notice staker registered - /// @param addr staker address - /// @param tmKey tendermint pubkey - /// @param blsKey BLS pubkey - event Registered(address addr, bytes32 tmKey, bytes blsKey); - - /// @notice stakers removed - /// @param stakers stakers removed - event StakersRemoved(address[] stakers); - - /// @notice Withdrawn - /// @param addr staker address - /// @param unlockHeight unlock block height - event Withdrawn(address indexed addr, uint256 unlockHeight); - - /// @notice staker claimed - /// @param staker staker claimed - /// @param receiver receiver address - event Claimed(address indexed staker, address receiver); - - /// @notice stakers were slashed - /// @param stakers slashed stakers - event Slashed(address[] stakers); - - /// @notice slash remaining claimed - /// @param receiver receiver address - /// @param amount claimed amount - event SlashRemainingClaimed(address receiver, uint256 amount); - - /// @notice whitelist updated - /// @param add addresses added - /// @param remove addresses removed - event WhitelistUpdated(address[] add, address[] remove); - - /// @notice staking value updated - /// @param oldStakingValue old staking value - /// @param newStakingValue new staking value - event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue); - - /// @notice gas limit add staker updated - /// @param oldGasLimit old gas limit - /// @param newGasLimit new gas limit - event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit); - - /// @notice gas limit remove stakers updated - /// @param oldGasLimit old gas limit - /// @param newGasLimit new gas limit - event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit); - - /// @notice reward percentage updated - /// @param oldPercentage old percentage - /// @param newPercentage new percentage - event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage); - - /// @notice challenge deposit value updated - /// @param oldChallengeDeposit old challengeDeposit - /// @param newChallengeDeposit new challengeDeposit - event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit); - - /************************* - * Public View Functions * - *************************/ - - /// @notice return all stakers - function getStakers() external view returns (address[255] memory); - - /// @notice return active stakers - function getActiveStakers() external view returns (address[] memory); - - /// @notice return staking value - function stakingValue() external view returns (uint256); - - /// @notice return challenge deposit value - function challengeDeposit() external view returns (uint256); - - /// @notice whether address is staker - /// @param addr the address to check - function isStaker(address addr) external view returns (bool); - - /// @notice whether address is active staker - /// @param addr the address to check - function isActiveStaker(address addr) external view returns (bool); - - /// @notice get staker bitmap - /// @param staker the staker address - function getStakerBitmap(address staker) external view returns (uint256); - - /// @notice get stakers bitmap - /// @param stakers the staker address array - function getStakersBitmap(address[] calldata stakers) external view returns (uint256); - - /// @notice verify BLS signature - /// @param signedSequencersBitmap bitmap of signed sequencers - /// @param sequencerSet sequencer set - /// @param msgHash bls message hash - /// @param signature batch signature - function verifySignature( - uint256 signedSequencersBitmap, - address[] calldata sequencerSet, - bytes32 msgHash, - bytes calldata signature - ) external view returns (bool); - - /***************************** - * Public Mutating Functions * - *****************************/ - - /// @notice challenger win, slash sequencers - /// @param sequencersBitmap the sequencers to slash - function slash(uint256 sequencersBitmap) external returns (uint256); -} diff --git a/contracts/contracts/l1/staking/L1Staking.sol b/contracts/contracts/l1/staking/L1Staking.sol deleted file mode 100644 index 165fec18d..000000000 --- a/contracts/contracts/l1/staking/L1Staking.sol +++ /dev/null @@ -1,515 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; - -import {Predeploys} from "../../libraries/constants/Predeploys.sol"; -import {Types} from "../../libraries/common/Types.sol"; -import {Staking} from "../../libraries/staking/Staking.sol"; -import {IL1Staking} from "./IL1Staking.sol"; -import {IL2Staking} from "../../l2/staking/IL2Staking.sol"; - -contract L1Staking is IL1Staking, Staking, OwnableUpgradeable, ReentrancyGuardUpgradeable { - /************* - * Variables * - *************/ - - /// @notice rollup Contract - address public rollupContract; - - /// @notice staking value - uint256 public stakingValue; - - /// @notice exit lock blocks - uint256 public withdrawalLockBlocks; - - /// @notice percentage awarded to challenger - uint256 public rewardPercentage; - - /// @notice cross-chain gas limit add staker - uint256 public gasLimitAddStaker; - - /// @notice cross-chain gas limit remove stakers - uint256 public gasLimitRemoveStakers; - - /// @notice slash remaining - uint256 public slashRemaining; - - /// @notice staker whitelist - mapping(address stakerAddr => bool inWhitelist) public whitelist; - - /// @notice staker removed list - mapping(address stakerAddr => bool removed) public removedList; - - /// @notice all stakers (0-254) - address[255] public stakerSet; - - /// @notice all stakers indexes (1-255). '0' means not exist. stakerIndexes[1] releated to stakerSet[0] - mapping(address stakerAddr => uint8 index) public stakerIndexes; - - /// @notice stakers to delete - address[] public deleteList; - - /// @notice staker deleteable height - mapping(address stakerAddr => uint256 height) public deleteableHeight; - - /// @notice all stakers info - mapping(address stakerAddr => Types.StakerInfo) public stakers; - - /// @notice bls key map - mapping(bytes blsPubkey => bool exist) public blsKeys; - - /// @notice tendermint key map - mapping(bytes32 tmPubkey => bool exist) public tmKeys; - - /// @notice withdraw unlock block height - mapping(address staker => uint256 amount) public withdrawals; - - /// @notice challenge deposit value - uint256 public challengeDeposit; - - /********************** - * Function Modifiers * - **********************/ - - /// @notice whether in whitelist - modifier inWhitelist(address addr) { - require(whitelist[addr], "not in whitelist"); - _; - } - - /// @notice only rollup contract - modifier onlyRollupContract() { - require(_msgSender() == rollupContract, "only rollup contract"); - _; - } - - /*************** - * Constructor * - ***************/ - - /// @param _messenger Address of CrossDomainMessenger on this network. - constructor(address payable _messenger) Staking(_messenger, payable(Predeploys.L2_STAKING)) { - _disableInitializers(); - } - - /*************** - * Initializer * - ***************/ - - /// @notice initializer - /// @param _rollupContract rollup contract address - /// @param _stakingValue staking value - /// @param _challengeDeposit challenge deposit value - /// @param _lockBlocks withdraw lock blocks - /// @param _rewardPercentage percentage awarded to challenger - /// @param _gasLimitAdd cross-chain gas limit add staker - /// @param _gasLimitRemove cross-chain gas limit remove stakers - function initialize( - address _rollupContract, - uint256 _stakingValue, - uint256 _challengeDeposit, - uint256 _lockBlocks, - uint256 _rewardPercentage, - uint256 _gasLimitAdd, - uint256 _gasLimitRemove - ) public initializer { - require(_rollupContract != address(0), "invalid rollup contract"); - require(_stakingValue > 0, "invalid staking value"); - require(_challengeDeposit > 0, "invalid challenge deposit value"); - require(_lockBlocks > 0, "invalid withdrawal lock blocks"); - require(_gasLimitAdd > 0, "invalid gas limit add staker"); - require(_gasLimitRemove > 0, "invalid gas limit remove stakers"); - require(_rewardPercentage > 0 && _rewardPercentage <= 100, "invalid challenger reward percentage"); - - __Ownable_init(); - __ReentrancyGuard_init(); - - rollupContract = _rollupContract; - rewardPercentage = _rewardPercentage; - stakingValue = _stakingValue; - challengeDeposit = _challengeDeposit; - withdrawalLockBlocks = _lockBlocks; - gasLimitAddStaker = _gasLimitAdd; - gasLimitRemoveStakers = _gasLimitRemove; - - emit GasLimitAddStakerUpdated(0, _gasLimitAdd); - emit GasLimitRemoveStakersUpdated(0, _gasLimitRemove); - emit RewardPercentageUpdated(0, _rewardPercentage); - } - - /************************ - * Restricted Functions * - ************************/ - - /// @notice update whitelist - function updateWhitelist(address[] calldata add, address[] calldata remove) external onlyOwner { - for (uint256 i = 0; i < add.length; i++) { - require(!removedList[add[i]], "in removed list"); - whitelist[add[i]] = true; - } - for (uint256 i = 0; i < remove.length; i++) { - delete whitelist[remove[i]]; - } - emit WhitelistUpdated(add, remove); - } - - /// @notice register staker - /// @param tmKey tendermint pubkey - /// @param blsKey bls pubkey - function register(bytes32 tmKey, bytes memory blsKey) external payable inWhitelist(_msgSender()) { - require(stakers[_msgSender()].addr == address(0), "already registered"); - require(tmKey != 0 && !tmKeys[tmKey], "invalid tendermint pubkey"); - require(blsKey.length == 256 && !blsKeys[blsKey], "invalid bls pubkey"); - require(msg.value == stakingValue, "invalid staking value"); - - stakers[_msgSender()] = Types.StakerInfo(_msgSender(), tmKey, blsKey); - _addStaker(_msgSender()); - blsKeys[blsKey] = true; - tmKeys[tmKey] = true; - emit Registered(_msgSender(), tmKey, blsKey); - - // send message to add staker on l2 - _msgAddStaker(stakers[_msgSender()]); - } - - /// @notice remove staker - function removeStaker(address[] memory _stakers) external onlyOwner { - for (uint256 i = 0; i < _stakers.length; i++) { - require(isActiveStaker(_stakers[i]), "only active staker can be removed"); - require(withdrawals[_stakers[i]] == 0, "withdrawing"); - - withdrawals[_stakers[i]] = block.number + withdrawalLockBlocks; - _removeStaker(_stakers[i]); - emit Withdrawn(_stakers[i], withdrawals[_stakers[i]]); - - delete whitelist[_stakers[i]]; - removedList[_stakers[i]] = true; - } - emit StakersRemoved(_stakers); - - // send message to remove stakers on l2 - _msgRemoveStakers(_stakers); - } - - /// @notice withdraw staking - function withdraw() external { - require(isActiveStaker(_msgSender()), "only active staker"); - require(withdrawals[_msgSender()] == 0, "withdrawing"); - - withdrawals[_msgSender()] = block.number + withdrawalLockBlocks; - _removeStaker(_msgSender()); - emit Withdrawn(_msgSender(), withdrawals[_msgSender()]); - - delete whitelist[_msgSender()]; - removedList[_msgSender()] = true; - - address[] memory remove = new address[](1); - remove[0] = _msgSender(); - emit StakersRemoved(remove); - - // send message to remove staker on l2 - _msgRemoveStakers(remove); - } - - /// @notice challenger win, slash sequencers - function slash(uint256 sequencersBitmap) external onlyRollupContract nonReentrant returns (uint256) { - address[] memory sequencers = getStakersFromBitmap(sequencersBitmap); - - uint256 valueSum; - for (uint256 i = 0; i < sequencers.length; i++) { - if (withdrawals[sequencers[i]] > 0) { - delete withdrawals[sequencers[i]]; - valueSum += stakingValue; - } else if (!isStakerInDeleteList(sequencers[i])) { - // If it is the first time to be slashed - valueSum += stakingValue; - _removeStaker(sequencers[i]); - // remove from whitelist - delete whitelist[sequencers[i]]; - removedList[sequencers[i]] = true; - } - } - - uint256 reward = (valueSum * rewardPercentage) / 100; - slashRemaining += valueSum - reward; - _transfer(rollupContract, reward); - - emit Slashed(sequencers); - emit StakersRemoved(sequencers); - - // send message to remove stakers on l2 - _msgRemoveStakers(sequencers); - - return reward; - } - - /// @notice claim slash remaining - /// @param receiver receiver address - function claimSlashRemaining(address receiver) external onlyOwner nonReentrant { - uint256 _slashRemaining = slashRemaining; - _transfer(receiver, slashRemaining); - slashRemaining = 0; - emit SlashRemainingClaimed(receiver, _slashRemaining); - } - - /// @notice update staking value - /// @param _stakingValue staking value - function updateStakingValue(uint256 _stakingValue) external onlyOwner { - require(_stakingValue > 0 && _stakingValue != stakingValue, "invalid staking value"); - uint256 _oldStakingValue = stakingValue; - stakingValue = _stakingValue; - emit StakingValueUpdated(_oldStakingValue, stakingValue); - } - - /// @notice update gas limit of add staker - /// @param _gasLimitAdd cross-chain gas limit add staker - function updateGasLimitAddStaker(uint256 _gasLimitAdd) external onlyOwner { - require(_gasLimitAdd > 0 && _gasLimitAdd != gasLimitAddStaker, "invalid new gas limit"); - uint256 _oldGasLimitAddStaker = gasLimitAddStaker; - gasLimitAddStaker = _gasLimitAdd; - emit GasLimitAddStakerUpdated(_oldGasLimitAddStaker, _gasLimitAdd); - } - - /// @notice update gas limit of remove stakers - /// @param _gasLimitRemove cross-chain gas limit remove stakers - function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) external onlyOwner { - require(_gasLimitRemove > 0 && _gasLimitRemove != gasLimitRemoveStakers, "invalid new gas limit"); - uint256 _oldGasLimitRemove = gasLimitRemoveStakers; - gasLimitRemoveStakers = _gasLimitRemove; - emit GasLimitRemoveStakersUpdated(_oldGasLimitRemove, _gasLimitRemove); - } - - /// @notice update challenge deposit - /// @param _challengeDeposit challenge deposit value - function updateChallengeDeposit(uint256 _challengeDeposit) external onlyOwner { - require(_challengeDeposit > 0 && _challengeDeposit != challengeDeposit, "invalid challenge deposit value"); - uint256 _oldChallengeDeposit = challengeDeposit; - challengeDeposit = _challengeDeposit; - emit ChallengeDepositUpdated(_oldChallengeDeposit, _challengeDeposit); - } - - /// @notice update reward percentage - /// @param _rewardPercentage percentage awarded to challenger - function updateRewardPercentage(uint256 _rewardPercentage) external onlyOwner { - require( - _rewardPercentage > 0 && _rewardPercentage <= 100 && _rewardPercentage != rewardPercentage, - "invalid reward percentage" - ); - uint256 _oldRewardPercentage = rewardPercentage; - rewardPercentage = _rewardPercentage; - emit RewardPercentageUpdated(_oldRewardPercentage, _rewardPercentage); - } - - /// @notice clean staker store - function cleanStakerStore() external onlyOwner { - _cleanStakerStore(); - } - - /***************************** - * Public Mutating Functions * - *****************************/ - - /// @notice claim withdrawal - /// @param receiver receiver address - function claimWithdrawal(address receiver) external nonReentrant { - require(withdrawals[_msgSender()] > 0, "withdrawal not exist"); - require(withdrawals[_msgSender()] <= block.number, "withdrawal locked"); - - delete withdrawals[_msgSender()]; - _cleanStakerStore(); - - emit Claimed(_msgSender(), receiver); - - _transfer(receiver, stakingValue); - } - - /************************* - * Public View Functions * - *************************/ - - /// @notice verify BLS signature - function verifySignature( - uint256, // signedSequencersBitmap - address[] calldata, // sequencerSet - bytes32, // msgHash - bytes calldata // signature - ) external pure returns (bool) { - // TODO verify BLS signature - return true; - } - - /// @notice return all stakers - function getStakers() external view returns (address[255] memory) { - return stakerSet; - } - - /// @notice return active stakers - function getActiveStakers() external view returns (address[] memory) { - uint256 activeStakersNumber; - bool[] memory tags = new bool[](255); - for (uint256 i = 0; i < 255; i++) { - // valid address and not in delete list - if (stakerSet[i] != address(0) && deleteableHeight[stakerSet[i]] == 0) { - activeStakersNumber++; - tags[i] = true; - } - } - address[] memory activeStakers = new address[](activeStakersNumber); - uint256 index; - for (uint256 i = 0; i < 255; i++) { - if (tags[i]) { - activeStakers[index] = stakerSet[i]; - index++; - } - } - return activeStakers; - } - - /// @notice whether address is staker - /// @param addr address to check - function isStaker(address addr) public view returns (bool) { - if (stakerIndexes[addr] == 0) { - return false; - } - return stakerSet[stakerIndexes[addr] - 1] == addr; - } - - /// @notice whether address is active staker - /// @param addr address to check - function isActiveStaker(address addr) public view returns (bool) { - if (stakerIndexes[addr] == 0) { - return false; - } - return (stakerSet[stakerIndexes[addr] - 1] == addr) && (deleteableHeight[addr] == 0); - } - - /// @notice whether address in delete list - /// @param addr address to check - function isStakerInDeleteList(address addr) public view returns (bool) { - return deleteableHeight[addr] > 0; - } - - /// @notice get staker bitmap - /// @param _staker the staker address - function getStakerBitmap(address _staker) external view returns (uint256 bitmap) { - require(isStaker(_staker), "invalid staker"); - bitmap = 1 << stakerIndexes[_staker]; - return bitmap; - } - - /// @notice get stakers bitmap - /// @param _stakers the staker address array - function getStakersBitmap(address[] calldata _stakers) external view returns (uint256 bitmap) { - require(_stakers.length <= 255, "stakers length out of bounds"); - for (uint256 i = 0; i < _stakers.length; i++) { - require(isStaker(_stakers[i]), "invalid staker"); - bitmap = bitmap | (1 << stakerIndexes[_stakers[i]]); - } - return bitmap; - } - - /// @notice get stakers from bitmap - /// @param bitmap the stakers bitmap - function getStakersFromBitmap(uint256 bitmap) public view returns (address[] memory stakerAddrs) { - // skip first bit - uint256 _bitmap = bitmap >> 1; - uint256 stakersLength = 0; - while (_bitmap > 0) { - stakersLength = stakersLength + 1; - _bitmap = _bitmap & (_bitmap - 1); - } - - stakerAddrs = new address[](stakersLength); - uint256 index = 0; - for (uint8 i = 1; i <= 255; i++) { - if ((bitmap & (1 << i)) > 0) { - stakerAddrs[index] = stakerSet[i - 1]; - index = index + 1; - if (index >= stakersLength) { - break; - } - } - } - } - - /********************** - * Internal Functions * - **********************/ - - /// @notice add stater - /// @param addr staker address - function _addStaker(address addr) internal { - for (uint8 i = 0; i < 255; i++) { - if (stakerSet[i] == address(0)) { - stakerSet[i] = addr; - stakerIndexes[addr] = i + 1; - return; - } - } - require(false, "slot full"); - } - - /// @notice Add staker to deleteList, it will not be actually deleted until cleanStakerStore is executed - /// @param addr staker address - function _removeStaker(address addr) internal { - require(deleteableHeight[addr] == 0, "already in deleteList"); - deleteList.push(addr); - deleteableHeight[addr] = block.number + withdrawalLockBlocks; - } - - /// @notice transfer ETH - /// @param _to The address to transfer ETH to. - /// @param _amount The amount of ETH to transfer. - function _transfer(address _to, uint256 _amount) internal { - if (_amount > 0) { - (bool success, ) = _to.call{value: _amount}(""); - require(success, "Rollup: ETH transfer failed"); - } - } - - /// @notice add staker - /// @param add staker to add - function _msgAddStaker(Types.StakerInfo memory add) internal { - MESSENGER.sendMessage( - address(OTHER_STAKING), - 0, - abi.encodeCall(IL2Staking.addStaker, (add)), - gasLimitAddStaker - ); - } - - /// @notice remove stakers - /// @param remove stakers to remove - function _msgRemoveStakers(address[] memory remove) internal { - MESSENGER.sendMessage( - address(OTHER_STAKING), - 0, - abi.encodeCall(IL2Staking.removeStakers, (remove)), - gasLimitRemoveStakers - ); - } - - /// @notice clean staker store - function _cleanStakerStore() internal { - uint256 i = 0; - while (i < deleteList.length) { - if (deleteableHeight[deleteList[i]] <= block.number) { - // clean stakerSet - delete stakerSet[stakerIndexes[deleteList[i]] - 1]; - delete stakerIndexes[deleteList[i]]; - - // clean staker info - delete stakers[deleteList[i]]; - - // clean deleteList - delete deleteableHeight[deleteList[i]]; - deleteList[i] = deleteList[deleteList.length - 1]; - deleteList.pop(); - } else { - i++; - } - } - } -} diff --git a/contracts/contracts/test/L1Staking.t.sol b/contracts/contracts/test/L1Staking.t.sol deleted file mode 100644 index 825e5040f..000000000 --- a/contracts/contracts/test/L1Staking.t.sol +++ /dev/null @@ -1,1154 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity =0.8.24; - -import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; - -import {Predeploys} from "../libraries/constants/Predeploys.sol"; -import {Types} from "../libraries/common/Types.sol"; -import {IL1Staking} from "../l1/staking/IL1Staking.sol"; -import {L1Staking} from "../l1/staking/L1Staking.sol"; -import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; - -// import "forge-std/console.sol"; - -contract StakingInitializeTest is L1MessageBaseTest { - function test_initialize_initializeAgain_revert() external { - // verify the initialize only can be called once. - hevm.expectRevert("Initializable: contract is already initialized"); - l1Staking.initialize( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ); - } - - function test_initialize_rollupZeroAddress_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid rollup contract. - hevm.expectRevert("invalid rollup contract"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(0), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_stakingValueEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid staking value. - hevm.expectRevert("invalid staking value"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - 0, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_challengeDepositEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid staking value. - hevm.expectRevert("invalid challenge deposit value"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, 0, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, defaultGasLimitRemove) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_lockBlocksEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid withdrawal lock blocks. - hevm.expectRevert("invalid withdrawal lock blocks"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - 0, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_gasLimitAddEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid gas limit add staker. - hevm.expectRevert("invalid gas limit add staker"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, 0, defaultGasLimitRemove) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_gasLimitRemoveEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid gas limit remove stakers. - hevm.expectRevert("invalid gas limit remove stakers"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, rewardPercentage, defaultGasLimitAdd, 0) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_rewardPercentageEqZero_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid challenger reward percentage. - hevm.expectRevert("invalid challenger reward percentage"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - 0, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_rewardPercentageEq101_revert() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Expect revert due to invalid challenger reward percentage. - hevm.expectRevert("invalid challenger reward percentage"); - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - ( - address(1), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - 101, - defaultGasLimitAdd, - defaultGasLimitRemove - ) - ) - ); - hevm.stopPrank(); - } - - function test_initialize_succeeds() external { - hevm.startPrank(multisig); - - // Deploy a proxy contract for l1StakingProxyTemp. - TransparentUpgradeableProxy l1StakingProxyTemp = new TransparentUpgradeableProxy( - address(emptyContract), - address(multisig), - new bytes(0) - ); - - // Verify the GasLimitAddStakerUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.GasLimitAddStakerUpdated(0, 22); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.GasLimitRemoveStakersUpdated(0, 33); - - // Verify the RewardPercentageUpdated event is emitted successful. - hevm.expectEmit(false, false, false, true); - emit IL1Staking.RewardPercentageUpdated(0, 11); - - ITransparentUpgradeableProxy(address(l1StakingProxyTemp)).upgradeToAndCall( - address(l1StakingImpl), - abi.encodeCall( - L1Staking.initialize, - (address(1), STAKING_VALUE, CHALLENGE_DEPOSIT, LOCK_BLOCKS, 11, 22, 33) - ) - ); - hevm.stopPrank(); - } -} - -contract StakingTest is L1MessageBaseTest { - function test_setUpCheck_succeeds() external { - assertEq(rollup.l1StakingContract(), address(l1Staking)); - assertEq(address(l1Staking.OTHER_STAKING()), address(Predeploys.L2_STAKING)); - assertEq(address(l1Staking.MESSENGER()), address(l1CrossDomainMessenger)); - assertEq(l1Staking.rollupContract(), address(rollup)); - assertEq(l1Staking.stakingValue(), STAKING_VALUE); - assertEq(l1Staking.withdrawalLockBlocks(), LOCK_BLOCKS); - assertEq(l1Staking.rewardPercentage(), rewardPercentage); - assertEq(l1Staking.gasLimitAddStaker(), 1000000); - assertEq(l1Staking.gasLimitRemoveStakers(), 10000000); - } - - function test_invalidStaker_reverts() external { - // make param - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - hevm.startPrank(address(emptyContract)); - hevm.expectRevert("invalid staker"); - l1Staking.getStakersBitmap(sequencers); - hevm.stopPrank(); - } - - function test_registerAlice_succeeds() external { - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(alice); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); - } - - function test_stakerWithdrawAndClaim_succeeds() external { - // register - - hevm.deal(bob, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(bob); - address[] memory add = new address[](1); - add[0] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(bob); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(bob, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(bob); - assertEq(addrCheck, bob); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); - - // withdraw - - hevm.prank(bob); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Withdrawn(bob, block.number + LOCK_BLOCKS); - l1Staking.withdraw(); - assertFalse(l1Staking.whitelist(bob)); - assertTrue(l1Staking.isStaker(bob)); - assertTrue(l1Staking.isStakerInDeleteList(bob)); - assertTrue(l1Staking.removedList(bob)); - assertEq(l1Staking.withdrawals(bob), block.number + LOCK_BLOCKS); - hevm.stopPrank(); - - // claim - - hevm.prank(bob); - assertEq(bob.balance, 4 * STAKING_VALUE); - hevm.roll(block.number + LOCK_BLOCKS + 1); - l1Staking.claimWithdrawal(bob); - assertEq(bob.balance, 5 * STAKING_VALUE); - assertEq(l1Staking.withdrawals(bob), 0); - hevm.stopPrank(); - } - - function test_stakersBitmap_succeeds() external { - address[] memory stakersAddr = new address[](255); - for (uint256 i = 0; i < 255; i++) { - stakersAddr[i] = address(bytes20(bytes32(keccak256(abi.encodePacked(1500 + i))))); - hevm.deal(stakersAddr[i], 5 * STAKING_VALUE); - } - hevm.prank(multisig); - l1Staking.updateWhitelist(stakersAddr, new address[](0)); - - for (uint256 i = 0; i < 255; i++) { - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(stakersAddr[i]); - hevm.startPrank(stakersAddr[i]); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - hevm.stopPrank(); - } - - uint256 bitmap = l1Staking.getStakersBitmap(stakersAddr); - address[] memory stakersConvert = l1Staking.getStakersFromBitmap(bitmap); - assertEq(stakersAddr.length, stakersConvert.length); - assertEq(stakersAddr[0], stakersConvert[0]); - assertEq(stakersAddr[stakersAddr.length - 1], stakersConvert[stakersConvert.length - 1]); - - // console.logString("......................"); - // console.logUint(bitmap); - // console.logUint(stakersAddr.length); - // console.logUint(stakersConvert.length); - // console.logString("......................"); - } - - function test_slash_succeeds() external { - // TODO - } - - function test_updateParams_succeeds() external { - // TODO - } -} - -contract StakingWhitelistTest is L1MessageBaseTest { - function test_whitelist_notOwner_reverts() external { - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateWhitelist(add, new address[](0)); - } - - function test_whitelist_add_succeeds() external { - // make add param - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - - // Verify the WhitelistUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.WhitelistUpdated(add, new address[](0)); - - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - } - - function test_whitelist_remove_succeeds() external { - address[] memory add = new address[](1); - add[0] = alice; - address[] memory remove = new address[](1); - remove[0] = bob; - - // Verify the WhitelistUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.WhitelistUpdated(add, remove); - - hevm.prank(multisig); - l1Staking.updateWhitelist(add, remove); - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - } - - function test_whitelist_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_whitelist_reAdd_inRemovedList_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - - hevm.startPrank(multisig); - address[] memory reAdd = new address[](1); - reAdd[0] = bob; - hevm.expectRevert("in removed list"); - l1Staking.updateWhitelist(reAdd, new address[](0)); - hevm.stopPrank(); - } - - function test_whitelist_slash_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - assertEq(bitmap, 4); - address[] memory stakers = l1Staking.getStakersFromBitmap(bitmap); - assertEq(stakers.length, 1); - assertEq(stakers[0], bob); - hevm.prank(l1Staking.rollupContract()); - l1Staking.slash(bitmap); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } -} - -contract StakingRegisterTest is L1MessageBaseTest { - function test_register_notInWhitelist_reverts() external { - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("not in whitelist"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_alreadyRegistered_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - hevm.expectRevert("already registered"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notStakingValue_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid staking value"); - l1Staking.register{value: STAKING_VALUE - 1}(aliceInfo.tmKey, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notTmKey_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid tendermint pubkey"); - l1Staking.register{value: STAKING_VALUE}(0, aliceInfo.blsKey); - hevm.stopPrank(); - } - - function test_register_notBlsKey_reverts() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.startPrank(alice); - hevm.expectRevert("invalid bls pubkey"); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, ""); - hevm.stopPrank(); - } - - function test_register_succeeds() external { - // add to whitelist - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - - (address addressCheck, , ) = l1Staking.stakers(alice); - assertEq(addressCheck, address(0)); - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - assertFalse(l1Staking.blsKeys(aliceInfo.blsKey)); - assertFalse(l1Staking.tmKeys(aliceInfo.tmKey)); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, aliceInfo.tmKey); - assertBytesEq(blsKeyCheck, aliceInfo.blsKey); - assertTrue(l1Staking.blsKeys(aliceInfo.blsKey)); - assertTrue(l1Staking.tmKeys(aliceInfo.tmKey)); - } -} - -contract StakingWithdrawTest is L1MessageBaseTest { - function test_withdraw_notStaker_reverts() external { - // bob withdraw - hevm.expectRevert("only active staker"); - hevm.startPrank(bob); - l1Staking.withdraw(); - hevm.stopPrank(); - } - - function test_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // before withdraw - assertEq(l1Staking.withdrawals(bob), 0); - assertTrue(l1Staking.isStaker(bob)); - assertFalse(l1Staking.removedList(bob)); - - // Verify the StakersRemoved event is emitted successfully. - address[] memory remove = new address[](1); - remove[0] = bob; - hevm.expectEmit(true, true, true, true); - emit IL1Staking.StakersRemoved(remove); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // after withdraw - // check - assertEq(l1Staking.withdrawals(bob), block.number + l1Staking.withdrawalLockBlocks()); - assertTrue(l1Staking.isStaker(bob)); - assertTrue(l1Staking.isStakerInDeleteList(bob)); - - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } -} - -contract StakingRemoveStakerTest is L1MessageBaseTest { - // TODO -} - -contract StakingSlashTest is L1MessageBaseTest { - function test_slash_notRollup_reverts() external { - hevm.startPrank(address(emptyContract)); - hevm.expectRevert("only rollup contract"); - l1Staking.slash(0); - hevm.stopPrank(); - } - - function test_slash_withdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_slash_notWithdraw_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - // bob sequencer to slash - uint256 bitmap = l1Staking.getStakerBitmap(bob); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - - // check - assertTrue(l1Staking.whitelist(alice)); - assertFalse(l1Staking.whitelist(bob)); - assertFalse(l1Staking.removedList(alice)); - assertTrue(l1Staking.removedList(bob)); - } - - function test_slash_all_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - uint256 beforeBalance = l1Staking.rollupContract().balance; - - // Verify the Slashed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Slashed(sequencers); - - // Verify the StakersRemoved event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.StakersRemoved(sequencers); - - // sequencer to slash - uint256 bitmap = l1Staking.getStakersBitmap(sequencers); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - uint256 afterBalance = l1Staking.rollupContract().balance; - assertEq(reward, afterBalance - beforeBalance); - } -} - -contract StakingClaimSlashRemainingTest is L1MessageBaseTest { - function test_claimSlashRemaining_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.claimSlashRemaining(bob); - } - - function test_claimSlashRemaining_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.stopPrank(); - - address[] memory sequencers = new address[](2); - sequencers[0] = alice; - sequencers[1] = bob; - uint256 beforeBalance = l1Staking.rollupContract().balance; - - // sequencer to slash - uint256 bitmap = l1Staking.getStakersBitmap(sequencers); - hevm.prank(l1Staking.rollupContract()); - uint256 reward = l1Staking.slash(bitmap); - assertEq(reward, (2 * STAKING_VALUE * l1Staking.rewardPercentage()) / 100); - uint256 afterBalance = l1Staking.rollupContract().balance; - assertEq(reward, afterBalance - beforeBalance); - - // Verify the SlashRemainingClaimed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.SlashRemainingClaimed(multisig, 2 * STAKING_VALUE - reward); - - uint256 beforeBalanceOfM = multisig.balance; - hevm.prank(multisig); - l1Staking.claimSlashRemaining(multisig); - uint256 afterBalanceOfM = multisig.balance; - emit log_uint(STAKING_VALUE * 2); - emit log_uint(afterBalanceOfM - beforeBalanceOfM); - emit log_uint(reward); - uint256 remaining = 2 * STAKING_VALUE - reward; - assertEq(afterBalanceOfM - beforeBalanceOfM, remaining); - } -} - -contract StakingUpdateGasLimitAddStakerTest is L1MessageBaseTest { - function test_updateGasLimitAddStaker_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateGasLimitAddStaker(0); - } - - function test_updateGasLimitAddStaker_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitAddStaker(0); - // defaultGasLimitAdd - } - - function test_updateGasLimitAddStaker_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitAddStaker(defaultGasLimitAdd); - } - - function test_updateGasLimitAddStaker_succeeds() external { - uint256 newValue = defaultGasLimitAdd / 10; - uint256 oldValue = l1Staking.gasLimitAddStaker(); - - // Verify the GasLimitAddStakerUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.GasLimitAddStakerUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateGasLimitAddStaker(newValue); - assertEq(l1Staking.gasLimitAddStaker(), newValue); - } -} - -contract StakingUpdateGasLimitRemoveStakersTest is L1MessageBaseTest { - function test_updateGasLimitRemoveStakers_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateGasLimitRemoveStakers(0); - } - - function test_updateGasLimitRemoveStakers_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitRemoveStakers(0); - } - - function test_updateGasLimitRemoveStakers_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid new gas limit"); - l1Staking.updateGasLimitRemoveStakers(defaultGasLimitRemove); - } - - function test_updateGasLimitRemoveStakers_succeeds() external { - uint256 newValue = defaultGasLimitRemove / 10; - uint256 oldValue = l1Staking.gasLimitRemoveStakers(); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.GasLimitRemoveStakersUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateGasLimitRemoveStakers(newValue); - assertEq(l1Staking.gasLimitRemoveStakers(), newValue); - } -} - -contract StakingUpdateRewardPercentageTest is L1MessageBaseTest { - function test_updateRewardPercentage_notOwner_reverts() external { - hevm.prank(alice); - hevm.expectRevert("Ownable: caller is not the owner"); - l1Staking.updateRewardPercentage(0); - } - - function test_updateRewardPercentage_eqZero_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(0); - } - - function test_updateRewardPercentage_ge100_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(101); - } - - function test_updateRewardPercentage_eqDefaultValue_reverts() external { - hevm.prank(multisig); - hevm.expectRevert("invalid reward percentage"); - l1Staking.updateRewardPercentage(rewardPercentage); - } - - function test_updateRewardPercentage_succeeds() external { - uint256 newValue = 66; - uint256 oldValue = l1Staking.rewardPercentage(); - - // Verify the GasLimitRemoveStakersUpdated event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.RewardPercentageUpdated(oldValue, newValue); - - hevm.prank(multisig); - l1Staking.updateRewardPercentage(newValue); - assertEq(l1Staking.rewardPercentage(), newValue); - } -} - -contract StakingClaimWithdrawalTest is L1MessageBaseTest { - function test_claimWithdrawal_notWithdraw_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - hevm.expectRevert("withdrawal not exist"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_locked_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - hevm.expectRevert("withdrawal locked"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_eqLockedBlockNumber_reverts() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - - // set block number - hevm.roll(block.number + l1Staking.withdrawalLockBlocks() - 1); - hevm.expectRevert("withdrawal locked"); - l1Staking.claimWithdrawal(bob); - hevm.stopPrank(); - } - - function test_claimWithdrawal_succeeds() external { - // add to whitelist - address[] memory add = new address[](2); - add[0] = alice; - add[1] = bob; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - assertTrue(l1Staking.whitelist(alice)); - assertTrue(l1Staking.whitelist(bob)); - - // alice register - Types.StakerInfo memory aliceInfo = ffi.generateStakerInfo(alice); - hevm.deal(alice, 5 * STAKING_VALUE); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(aliceInfo.tmKey, aliceInfo.blsKey); - - // bob register - Types.StakerInfo memory bobInfo = ffi.generateStakerInfo(bob); - hevm.deal(bob, 5 * STAKING_VALUE); - hevm.startPrank(bob); - l1Staking.register{value: STAKING_VALUE}(bobInfo.tmKey, bobInfo.blsKey); - - // bob withdraw - l1Staking.withdraw(); - - // Verify the Claimed event is emitted successfully. - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Claimed(bob, bob); - - // set block number - hevm.roll(block.number + l1Staking.withdrawalLockBlocks() + 1); - uint256 beforeBalance = bob.balance; - l1Staking.claimWithdrawal(bob); - uint256 afterBalance = bob.balance; - assertEq(afterBalance - beforeBalance, STAKING_VALUE); - hevm.stopPrank(); - } -} - -contract StakingVerifySignatureTest is L1MessageBaseTest { - // function testVerifySignature() external { - // l1Staking.verifySignature(); - // } -} diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index dbcc95c1c..a6ba32d15 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -2,9 +2,9 @@ pragma solidity =0.8.24; import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; -import {Types} from "../libraries/common/Types.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {IRollup} from "../l1/rollup/IRollup.sol"; -import {IL1Staking} from "../l1/staking/IL1Staking.sol"; +import {Rollup} from "../l1/rollup/Rollup.sol"; import {BatchHeaderCodecV0} from "../libraries/codec/BatchHeaderCodecV0.sol"; import {BatchHeaderCodecV1} from "../libraries/codec/BatchHeaderCodecV1.sol"; @@ -15,18 +15,10 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { bytes public batchHeader0; bytes32 public batchHash0; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - // Setup batch signature input - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - // Import genesis batch bytes memory _batchHeader0 = new bytes(249); bytes32 bytesData0 = bytes32(uint256(0)); @@ -45,23 +37,13 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { rollup.importGenesisBatch(batchHeader0); batchHash0 = rollup.committedBatches(0); - // Setup staker - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory addrs = new address[](1); - addrs[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(addrs, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - // Set rollupDelayPeriod (e.g., 1 hour) - no prank needed for hevm.store hevm.store(address(rollup), bytes32(ROLLUP_DELAY_PERIOD_SLOT), bytes32(uint256(3600))); } - /// @dev Helper to compute sequencerSetVerifyHash from sequencerSets - function _getSequencerSetVerifyHash() internal view returns (bytes32) { - return keccak256(batchSignatureInput.sequencerSets); + /// @dev The retained sequencer-set field is fixed to zero after the upgrade. + function _getSequencerSetVerifyHash() internal pure returns (bytes32) { + return bytes32(0); } /// @dev Helper to create batch header that matches what _commitBatchWithBatchData produces @@ -87,7 +69,7 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), prevStateRoot) // prevStateHash mstore(add(batchHeader1, add(0x20, 121)), postStateRoot) // postStateHash mstore(add(batchHeader1, add(0x20, 153)), withdrawalRoot) // withdrawRootHash - mstore(add(batchHeader1, add(0x20, 185)), sequencerSetVerifyHash) // sequencerSetVerifyHash = keccak256(sequencerSets) + mstore(add(batchHeader1, add(0x20, 185)), sequencerSetVerifyHash) // fixed zero field mstore(add(batchHeader1, add(0x20, 217)), _parentBatchHash) // parentBatchHash } } @@ -142,7 +124,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid timing"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -171,7 +152,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("invalid version"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -198,7 +178,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("V2 requires at least 1 blob"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -226,7 +205,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("Pausable: paused"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -254,7 +232,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("previous state root is zero"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -282,7 +259,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("new state root is zero"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -315,7 +291,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect parent batch hash"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -343,7 +318,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("incorrect previous state root"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, bytes("") ); @@ -376,7 +350,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -417,7 +390,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -451,7 +423,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, mockProof ); @@ -486,7 +457,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -542,7 +512,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.expectRevert("l1msg delay"); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -575,7 +544,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(bob); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -626,7 +594,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" ); @@ -661,7 +628,6 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1, hex"deadbeef" // Non-empty proof required ); @@ -680,16 +646,9 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { contract RollupCommitBatchTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); } function test_commitAndFinalizeWithL1Messages_succeeds() public { @@ -739,8 +698,7 @@ contract RollupCommitBatchTest is L1MessageBaseTest { // 0000000000000000000000000000000000000000000000000000000000000001 // 0000000000000000000000000000000000000000000000000000000000000002 // 0000000000000000000000000000000000000000000000000000000000000003 - // => sequencer set verify hash - // f1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 + // => sequencer set verify hash is the retained 32-byte zero field // => hash for parent batch header // 00847173b29b238cf319cde79512b7c213e5a8b4138daa7051914c4592b6dfc7 bytes memory batchHeader1 = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); @@ -754,29 +712,16 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), bytesData1) // prevStateHash mstore(add(batchHeader1, add(0x20, 121)), bytesData1) // postStateHash mstore(add(batchHeader1, add(0x20, 153)), bytesData3) // withdrawRootHash - mstore( - add(batchHeader1, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 - ) // sequencerSetVerifyHash + mstore(add(batchHeader1, add(0x20, 185)), 0) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash } uint64 lastBlockNumber = 1; uint16 numL1Messages = 1; - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), - abi.encode(true) - ); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), - abi.encode(2) - ); _setupDelayAndWarpForProof(); _mockVerifierForProof(); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); + emit IRollup.CommitBatch(1, keccak256(batchHeader1)); batchDataInput = IRollup.BatchDataInput( 0, batchHeader0, @@ -786,12 +731,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData3 ); - rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader1, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchHeader1, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(1)); bytes32 batchHash1 = rollup.committedBatches(1); - assertEq(batchHash1, bytes32(0xc1862b08d265f073817a8ce0d7cbb426c16d58a86b93464244ab1d027318642e)); + assertEq(batchHash1, keccak256(batchHeader1)); bytes32 stateRoot1 = rollup.committedStateRoots(1); assertEq(stateRoot1, bytesData1); @@ -826,28 +771,14 @@ contract RollupCommitBatchTest is L1MessageBaseTest { mstore(add(batchHeader2, add(0x20, 89)), bytesData1) // prevStateHash mstore(add(batchHeader2, add(0x20, 121)), bytesData1) // postStateHash mstore(add(batchHeader2, add(0x20, 153)), bytesData4) // withdrawRootHash - mstore( - add(batchHeader2, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 - ) // sequencerSetVerifyHash + mstore(add(batchHeader2, add(0x20, 185)), 0) // sequencerSetVerifyHash mstore(add(batchHeader2, add(0x20, 217)), batchHash1) // parentBatchHash mstore(add(batchHeader2, add(0x20, 249)), shl(192, lastBlockNumber)) // lastBlockNumber } - hevm.prank(multisig); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.isActiveStaker, (address(0))), - abi.encode(true) - ); - hevm.mockCall( - address(rollup.l1StakingContract()), - abi.encodeCall(IL1Staking.getStakerBitmap, (address(0))), - abi.encode(2) - ); hevm.startPrank(address(0)); hevm.expectEmit(true, true, false, true); - emit IRollup.CommitBatch(2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); + emit IRollup.CommitBatch(2, keccak256(batchHeader2)); batchDataInput = IRollup.BatchDataInput( 1, @@ -858,12 +789,12 @@ contract RollupCommitBatchTest is L1MessageBaseTest { bytesData1, bytesData4 ); - rollup.commitBatchWithProof(batchDataInput, batchSignatureInput, batchHeader2, hex"deadbeef"); + rollup.commitBatchWithProof(batchDataInput, batchHeader2, hex"deadbeef"); hevm.stopPrank(); assertFalse(rollup.isBatchFinalized(2)); bytes32 batchHash2 = rollup.committedBatches(2); - assertEq(batchHash2, bytes32(0x772132c2e12f21bfc5f2792838e480830f2c1dd2be0f3207b159905a9f321038)); + assertEq(batchHash2, keccak256(batchHeader2)); bytes32 stateRoot2 = rollup.committedStateRoots(2); assertEq(stateRoot2, bytesData1); @@ -889,36 +820,11 @@ contract RollupTest is L1MessageBaseTest { address public caller = address(0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84); bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - - // add staker - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.stopPrank(); - hevm.startPrank(alice); - hevm.expectEmit(true, true, true, true); - emit IL1Staking.Registered(alice, stakerInfo.tmKey, stakerInfo.blsKey); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); - (address addrCheck, bytes32 tmKeyCheck, bytes memory blsKeyCheck) = l1Staking.stakers(alice); - assertEq(addrCheck, alice); - assertEq(tmKeyCheck, stakerInfo.tmKey); - assertBytesEq(blsKeyCheck, stakerInfo.blsKey); - assertTrue(l1Staking.blsKeys(stakerInfo.blsKey)); - assertTrue(l1Staking.tmKeys(stakerInfo.tmKey)); - hevm.stopPrank(); + _registerAndStakeSubmitter(alice); } function test_commitBatches_succeeds() external { @@ -940,25 +846,25 @@ contract RollupTest is L1MessageBaseTest { } hevm.prank(multisig); rollup.importGenesisBatch(batchHeader0); - // only active staker allowed, revert + // only active submitter allowed, revert hevm.startPrank(address(0)); - hevm.expectRevert("only active staker allowed"); + hevm.expectRevert("only active submitter allowed"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // invalid version, revert (version 3+ is invalid; version 2 is now valid V2 multi-blob) hevm.startPrank(alice); hevm.expectRevert("invalid version"); batchDataInput = IRollup.BatchDataInput(3, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // batch header length incorrect, revert hevm.startPrank(alice); hevm.expectRevert("batch header length too small"); batchDataInput = IRollup.BatchDataInput(0, new bytes(120), 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // incorrect batch index, revert @@ -968,7 +874,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("incorrect batch index"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); assembly { mstore(add(batchHeader0, add(0x20, 1)), 0) // change back @@ -981,7 +887,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("incorrect parent batch hash"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); assembly { mstore(add(batchHeader0, add(0x20, 25)), 1) // change back @@ -992,14 +898,14 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("incorrect previous state root"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 0, 0, bytes32(uint256(2)), stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // incorrect batch header length, revert hevm.startPrank(alice); hevm.expectRevert("batch header length too small"); batchDataInput = IRollup.BatchDataInput(0, new bytes(248), 0, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); // commit batch with one chunk, no tx, correctly (commitBatch requires blob when no stored hash; use commitBatchWithProof) @@ -1014,7 +920,7 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, getTreeRoot(), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), rollup.committedBatches(0) ); hevm.startPrank(alice); @@ -1022,7 +928,6 @@ contract RollupTest is L1MessageBaseTest { hevm.deal(address(0), 10 ether); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); @@ -1033,7 +938,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("commitBatch requires no stored blob hash"); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, getTreeRoot()); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.stopPrank(); } @@ -1071,19 +976,18 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), batchHash0 ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); hevm.stopPrank(); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + assertEq(rollup.committedBatches(1), keccak256(batchHeader1ForProof)); // warp again so second commitBatchWithProof passes rollupDelay (batchDataStore[1].originTimestamp + period < block.timestamp) hevm.warp(block.timestamp + 3601); bytes memory batchHeader1 = new bytes(249); @@ -1097,10 +1001,7 @@ contract RollupTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), bytesData1) // prevStateHash mstore(add(batchHeader1, add(0x20, 121)), bytesData1) // postStateHash mstore(add(batchHeader1, add(0x20, 153)), bytesData4) // withdrawRootHash - mstore( - add(batchHeader1, add(0x20, 185)), - 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067 - ) // sequencerSetVerifyHash + mstore(add(batchHeader1, add(0x20, 185)), 0) // sequencerSetVerifyHash mstore(add(batchHeader1, add(0x20, 217)), batchHash0) // parentBatchHash mstore(add(batchHeader1, add(0x20, 249)), 0) // bitmap0 } @@ -1115,14 +1016,13 @@ contract RollupTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), rollup.committedBatches(1) ); hevm.startPrank(alice); batchDataInput = IRollup.BatchDataInput(0, batchHeader1, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader2ForProof, hex"deadbeef" ); @@ -1180,7 +1080,7 @@ contract RollupTest is L1MessageBaseTest { hevm.startPrank(alice); hevm.expectRevert("Pausable: paused"); batchDataInput = IRollup.BatchDataInput(0, new bytes(0), 0, 0, stateRoot, stateRoot, bytes32(uint256(4))); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); hevm.expectRevert("Pausable: paused"); rollup.finalizeBatch(new bytes(0)); @@ -1294,23 +1194,10 @@ contract RollupTest is L1MessageBaseTest { contract RollupCommitStateTest is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); IRollup.BatchDataInput public batchDataInput; - IRollup.BatchSignatureInput public batchSignatureInput; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory add = new address[](1); - add[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(add, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + _registerAndStakeSubmitter(alice); } function _genesisBatchHeader() internal pure returns (bytes memory batchHeader0) { @@ -1334,7 +1221,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { stateRoot, stateRoot, bytes32(uint256(4)), - keccak256(batchSignatureInput.sequencerSets), + bytes32(0), parentBatchHash ); } @@ -1353,7 +1240,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { mstore(add(batchHeader1, add(0x20, 89)), bytesData1) mstore(add(batchHeader1, add(0x20, 121)), bytesData1) mstore(add(batchHeader1, add(0x20, 153)), bytesData4) - mstore(add(batchHeader1, add(0x20, 185)), 0xf1f58308e98844ec99e2990d88bfb36e1a30f0e6591e62af90ae6f8498a1b067) + mstore(add(batchHeader1, add(0x20, 185)), 0) mstore(add(batchHeader1, add(0x20, 217)), parentBatchHash) mstore(add(batchHeader1, add(0x20, 249)), 0) } @@ -1373,7 +1260,6 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); @@ -1397,11 +1283,11 @@ contract RollupCommitStateTest is L1MessageBaseTest { hevm.prank(alice); rollup.commitBatchWithProof( batchDataInput, - batchSignatureInput, batchHeader1ForProof, hex"deadbeef" ); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + bytes32 expectedBatchHash = keccak256(batchHeader1ForProof); + assertEq(rollup.committedBatches(1), expectedBatchHash); assertGt(uint256(rollup.batchBlobVersionedHashes(1)), 0); // Revert batch 1 (blob hash is preserved) @@ -1415,8 +1301,8 @@ contract RollupCommitStateTest is L1MessageBaseTest { // Recommit with commitState (no blob in tx; uses stored blob hash) batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput, batchSignatureInput); - assertEq(rollup.committedBatches(1), 0x25c3e4fee90e53de960c1092746c431ab570eacf8513011902fa65f10c814541); + rollup.commitState(batchDataInput); + assertEq(rollup.committedBatches(1), expectedBatchHash); assertEq(uint256(rollup.lastCommittedBatchIndex()), 1); } @@ -1428,7 +1314,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); - rollup.commitState(batchDataInput, batchSignatureInput); + rollup.commitState(batchDataInput); // Without blob in tx, commitState succeeds. Revert "commitState must not carry blob" is hit only when blobhash(0) != 0 (blob tx). assertEq(rollup.lastCommittedBatchIndex(), 1); } @@ -1442,7 +1328,7 @@ contract RollupCommitStateTest is L1MessageBaseTest { batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); hevm.expectRevert("no stored blob hash for this batch"); - rollup.commitState(batchDataInput, batchSignatureInput); + rollup.commitState(batchDataInput); } /// @dev commitState can only be called by an active staker. @@ -1450,8 +1336,8 @@ contract RollupCommitStateTest is L1MessageBaseTest { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(address(1)); - hevm.expectRevert("only active staker allowed"); - rollup.commitState(batchDataInput, batchSignatureInput); + hevm.expectRevert("only active submitter allowed"); + rollup.commitState(batchDataInput); } /// @dev Mutual exclusion: (1) commitBatch reverts when stored blob hash exists; (2) commitState reverts when no stored hash (see test_commitState_reverts_when_no_stored_blob_hash). @@ -1465,36 +1351,190 @@ contract RollupCommitStateTest is L1MessageBaseTest { batchDataInput = IRollup.BatchDataInput(0, batchHeader0, 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); hevm.expectRevert("commitBatch requires no stored blob hash"); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); + } + +} + +contract RollupSubmitterUpgradeTest is L1MessageBaseTest { + uint256 internal constant LAST_FINALIZED_BATCH_INDEX_SLOT = 157; + uint256 internal constant LAST_COMMITTED_BATCH_INDEX_SLOT = 158; + uint256 internal constant BATCH_DATA_STORE_SLOT = 162; + uint256 internal constant IN_CHALLENGE_SLOT = 166; + uint256 internal constant REVERT_REQ_INDEX_SLOT = 168; + + function test_initialize4IsAtomicThroughProxyAdminAndRunsOnce() public { + Rollup nextImplementation = new Rollup(layer2ChainID); + bytes32 batchDataBase = keccak256(abi.encode(uint256(0), BATCH_DATA_STORE_SLOT)); + bytes32 legacyOwnerSlot = bytes32(uint256(batchDataBase) + 3); + bytes32 legacyValue = bytes32(uint256(0xAABBCC)); + hevm.store(address(rollup), legacyOwnerSlot, legacyValue); + bytes32 storedBlobSlot = keccak256(abi.encode(uint256(7), BATCH_BLOB_VERSIONED_HASHES_SLOT)); + hevm.store(address(rollup), storedBlobSlot, bytes32(uint256(0x1234))); + + hevm.prank(multisig); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rollup))), + address(nextImplementation), + abi.encodeCall(Rollup.initialize4, (address(submitter))) + ); + + assertEq(rollup.submitterContract(), address(submitter)); + assertEq(hevm.load(address(rollup), legacyOwnerSlot), legacyValue); + assertEq(rollup.batchBlobVersionedHashes(7), bytes32(uint256(0x1234))); + + hevm.prank(multisig); + hevm.expectRevert("Initializable: contract is already initialized"); + rollup.initialize4(address(submitter)); + } + + function test_initialize4ChecksDrainChallengeAndRevertBeforeCutover() public { + Rollup nextImplementation = new Rollup(layer2ChainID); + + hevm.store(address(rollup), bytes32(LAST_COMMITTED_BATCH_INDEX_SLOT), bytes32(uint256(1))); + hevm.prank(multisig); + hevm.expectRevert("pending batches"); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rollup))), + address(nextImplementation), + abi.encodeCall(Rollup.initialize4, (address(submitter))) + ); + + hevm.store(address(rollup), bytes32(LAST_COMMITTED_BATCH_INDEX_SLOT), bytes32(0)); + hevm.store(address(rollup), bytes32(LAST_FINALIZED_BATCH_INDEX_SLOT), bytes32(0)); + hevm.store(address(rollup), bytes32(IN_CHALLENGE_SLOT), bytes32(uint256(1))); + hevm.prank(multisig); + hevm.expectRevert("challenge in progress"); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rollup))), + address(nextImplementation), + abi.encodeCall(Rollup.initialize4, (address(submitter))) + ); + + hevm.store(address(rollup), bytes32(IN_CHALLENGE_SLOT), bytes32(0)); + hevm.store(address(rollup), bytes32(REVERT_REQ_INDEX_SLOT), bytes32(uint256(1))); + hevm.prank(multisig); + hevm.expectRevert("pending revert request"); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rollup))), + address(nextImplementation), + abi.encodeCall(Rollup.initialize4, (address(submitter))) + ); + + hevm.store(address(rollup), bytes32(REVERT_REQ_INDEX_SLOT), bytes32(0)); + hevm.prank(multisig); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rollup))), + address(nextImplementation), + abi.encodeCall(Rollup.initialize4, (address(submitter))) + ); + assertEq(rollup.submitterContract(), address(submitter)); } + function test_newSubmissionSelectors() public { + assertEq(IRollup.commitBatch.selector, bytes4(0x41f756da)); + assertEq(IRollup.commitState.selector, bytes4(0x67caa37a)); + assertEq(IRollup.commitBatchWithProof.selector, bytes4(0x1544ba3a)); + } +} + +contract RollupSubmitterIntegrationTest is L1MessageBaseTest { + bytes32 internal constant STATE_ROOT_1 = bytes32(uint256(1)); + bytes32 internal constant STATE_ROOT_2 = bytes32(uint256(2)); + bytes32 internal constant WITHDRAWAL_ROOT = bytes32(uint256(3)); + + function setUp() public virtual override { + super.setUp(); + _registerAndStakeSubmitter(alice); + hevm.deal(bob, 2 * CHALLENGE_DEPOSIT); + } + + function test_authorizedCommitStoresSubmitterAndZeroHeaderField() public { + bytes memory header0 = _importGenesis(); + bytes memory header1 = _commitState(header0); + + (, , , address accountableSubmitter) = rollup.batchDataStore(1); + assertEq(accountableSubmitter, alice); + bytes32 sequencerSetVerifyHash; + assembly { + sequencerSetVerifyHash := mload(add(add(header1, 0x20), 185)) + } + assertEq(sequencerSetVerifyHash, bytes32(0)); + assertEq(rollup.committedBatches(1), keccak256(header1)); + } + + function test_challengeUsesSubmitterDepositAndSlashesActualSubmitter() public { + bytes memory header1 = _commitState(_importGenesis()); + bytes32 batchHash = rollup.committedBatches(1); + + hevm.prank(bob); + hevm.expectRevert("insufficient value"); + rollup.challengeState{value: CHALLENGE_DEPOSIT - 1}(1, batchHash); + + hevm.prank(bob); + rollup.challengeState{value: CHALLENGE_DEPOSIT}(1, batchHash); + hevm.warp(block.timestamp + proofWindow + 1); + hevm.prank(alice); + rollup.proveState(header1, hex"deadbeef"); + + uint256 slashReward = (STAKING_VALUE * rewardPercentage) / 100; + assertEq(rollup.revertReqIndex(), 1); + assertEq(submitter.stakeOf(alice), 0); + assertFalse(submitter.registered(alice)); + assertEq(rollup.batchChallengeReward(bob), CHALLENGE_DEPOSIT + slashReward); + } + + function _importGenesis() internal returns (bytes memory header0) { + header0 = new bytes(BatchHeaderCodecV0.BATCH_HEADER_LENGTH); + bytes32 stateRoot = STATE_ROOT_1; + assembly { + mstore(add(header0, add(0x20, 25)), 1) + mstore(add(header0, add(0x20, 57)), 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014) + mstore(add(header0, add(0x20, 121)), stateRoot) + } + hevm.prank(multisig); + rollup.importGenesisBatch(header0); + } + + function _commitState(bytes memory header0) internal returns (bytes memory header1) { + _setStoredBlobHash(1); + _mockMessageQueueNotDelayedForProof(); + IRollup.BatchDataInput memory input = IRollup.BatchDataInput( + 0, + header0, + 1, + 0, + STATE_ROOT_1, + STATE_ROOT_2, + WITHDRAWAL_ROOT + ); + hevm.prank(alice); + rollup.commitState(input); + + header1 = _createBatchHeaderV0ForProof( + 1, + 0, + 0, + _computeDataHash(1, 0), + STATE_ROOT_1, + STATE_ROOT_2, + WITHDRAWAL_ROOT, + bytes32(0), + rollup.committedBatches(0) + ); + } } /// @dev Tests for Rollup V2 multi-blob batch header support (simplified: 257-byte header with aggregated blob hash). contract RollupCommitBatchV2Test is L1MessageBaseTest { bytes32 public stateRoot = bytes32(uint256(1)); - IRollup.BatchSignatureInput public batchSignatureInput; bytes public batchHeader0; bytes32 public batchHash0; function setUp() public virtual override { super.setUp(); - batchSignatureInput = IRollup.BatchSignatureInput( - uint256(0), - abi.encode(uint256(0), new address[](0), uint256(0), new address[](0), uint256(0), new address[](0)), - bytes("0x") - ); - - // Register staker - hevm.deal(alice, 5 * STAKING_VALUE); - Types.StakerInfo memory stakerInfo = ffi.generateStakerInfo(alice); - address[] memory addrs = new address[](1); - addrs[0] = alice; - hevm.prank(multisig); - l1Staking.updateWhitelist(addrs, new address[](0)); - hevm.prank(alice); - l1Staking.register{value: STAKING_VALUE}(stakerInfo.tmKey, stakerInfo.blsKey); + _registerAndStakeSubmitter(alice); // Import genesis batch (V0) bytes memory _genesis = new bytes(249); @@ -1529,7 +1569,7 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { mstore(add(p, 89), 0x0000000000000000000000000000000000000000000000000000000000000001) // prevStateHash mstore(add(p, 121), 0x0000000000000000000000000000000000000000000000000000000000000002) // postStateHash mstore(add(p, 153), 0x0000000000000000000000000000000000000000000000000000000000000003) // withdrawRootHash - mstore(add(p, 185), 0x0000000000000000000000000000000000000000000000000000000000000004) // seqSetVerifyHash + mstore(add(p, 185), 0) // seqSetVerifyHash mstore(add(p, 217), 0x0000000000000000000000000000000000000000000000000000000000000005) // parentBatchHash mstore(add(p, 249), shl(192, lastBlockNumber)) // lastBlockNumber } @@ -1571,7 +1611,7 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { hevm.prank(alice); hevm.expectRevert("V2 requires at least 1 blob"); - rollup.commitBatch(batchDataInput, batchSignatureInput); + rollup.commitBatch(batchDataInput); } /// @dev V2 _loadBatchHeader accepts a valid 257-byte V2 header (uses V1 loader). @@ -1661,7 +1701,7 @@ contract RollupCommitBatchV2Test is L1MessageBaseTest { bytes32 prevStateRoot = bytes32(uint256(0x1)); bytes32 postStateRoot = bytes32(uint256(0x2)); bytes32 withdrawRoot = bytes32(uint256(0x3)); - bytes32 seqVerifyHash = bytes32(uint256(0x4)); + bytes32 seqVerifyHash = bytes32(0); bytes32 dataHash = bytes32(uint256(0xDEAD)); bytes32 h0 = bytes32(uint256(0xAAAA)); bytes32 h1 = bytes32(uint256(0xBBBB)); diff --git a/contracts/contracts/test/Submitter.t.sol b/contracts/contracts/test/Submitter.t.sol new file mode 100644 index 000000000..51fe94d2b --- /dev/null +++ b/contracts/contracts/test/Submitter.t.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.24; + +import "forge-std/Test.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; +import {Submitter} from "../l1/rollup/Submitter.sol"; + +contract DrainRollupMock { + uint256 public lastCommittedBatchIndex; + uint256 public lastFinalizedBatchIndex; + + function setBatchIndexes(uint256 committed, uint256 finalized) external { + lastCommittedBatchIndex = committed; + lastFinalizedBatchIndex = finalized; + } + + function slash(ISubmitter submitterContract, address account) external returns (uint256) { + return submitterContract.slash(account); + } + + receive() external payable {} +} + +contract RejectEther { + receive() external payable { + revert("reject ether"); + } +} + +contract SubmitterTest is Test { + uint256 internal constant MINIMUM_STAKE = 1 ether; + uint256 internal constant CHALLENGE_DEPOSIT = 2 ether; + uint256 internal constant REWARD_PERCENTAGE = 25; + + address internal owner = address(0xA11CE); + address internal proxyAdmin = address(0xA11); + address internal alice = address(0xB0B); + address internal bob = address(0xCAFE); + + DrainRollupMock internal rollupMock; + Submitter internal implementation; + Submitter internal submitter; + + function setUp() public { + vm.deal(alice, 100 ether); + vm.deal(bob, 100 ether); + rollupMock = new DrainRollupMock(); + implementation = new Submitter(); + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(implementation), + proxyAdmin, + abi.encodeCall( + Submitter.initialize, + (owner, address(rollupMock), MINIMUM_STAKE, CHALLENGE_DEPOSIT, REWARD_PERCENTAGE) + ) + ); + submitter = Submitter(payable(address(proxy))); + } + + function test_initializeAndImplementationProtection() public { + assertEq(submitter.owner(), owner); + assertEq(submitter.rollupContract(), address(rollupMock)); + assertEq(submitter.minimumStake(), MINIMUM_STAKE); + assertEq(submitter.challengeDeposit(), CHALLENGE_DEPOSIT); + assertEq(submitter.rewardPercentage(), REWARD_PERCENTAGE); + + vm.expectRevert("Initializable: contract is already initialized"); + implementation.initialize(owner, address(rollupMock), 1, 1, 1); + vm.expectRevert("Initializable: contract is already initialized"); + submitter.initialize(owner, address(rollupMock), 1, 1, 1); + } + + function test_registrationStakeAndDynamicMinimum() public { + vm.prank(alice); + vm.expectRevert("Ownable: caller is not the owner"); + submitter.addSubmitter(alice); + + vm.prank(owner); + submitter.addSubmitter(alice); + assertFalse(submitter.isActive(alice)); + + vm.prank(alice); + vm.expectRevert("below minimum stake"); + submitter.stake{value: MINIMUM_STAKE - 1}(); + vm.prank(alice); + submitter.stake{value: MINIMUM_STAKE}(); + assertTrue(submitter.isActive(alice)); + + vm.prank(owner); + submitter.setMinimumStake(2 ether); + assertFalse(submitter.isActive(alice)); + + // A threshold increase must not prevent the account from exiting its existing stake. + vm.prank(alice); + submitter.withdraw(); + assertFalse(submitter.registered(alice)); + assertTrue(submitter.withdrawing(alice)); + } + + function test_withdrawWaitsForGlobalDrainAndRequiresOwnerToReauthorize() public { + _registerAndStake(alice); + rollupMock.setBatchIndexes(2, 1); + + vm.prank(alice); + submitter.withdraw(); + assertFalse(submitter.isActive(alice)); + assertFalse(submitter.registered(alice)); + assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + + vm.prank(alice); + vm.expectRevert("rollup not drained"); + submitter.claimWithdrawal(bob); + + rollupMock.setBatchIndexes(2, 2); + uint256 beforeBalance = bob.balance; + vm.prank(alice); + submitter.claimWithdrawal(bob); + assertEq(bob.balance - beforeBalance, MINIMUM_STAKE); + assertEq(submitter.stakeOf(alice), 0); + assertFalse(submitter.withdrawing(alice)); + + vm.prank(alice); + vm.expectRevert("not stakeable"); + submitter.stake{value: MINIMUM_STAKE}(); + vm.prank(owner); + submitter.addSubmitter(alice); + } + + function test_ownerRemovalUsesTheSameDrainGate() public { + _registerAndStake(alice); + rollupMock.setBatchIndexes(3, 2); + + vm.prank(owner); + submitter.removeSubmitter(alice); + assertFalse(submitter.registered(alice)); + assertTrue(submitter.withdrawing(alice)); + + vm.prank(alice); + vm.expectRevert("rollup not drained"); + submitter.claimWithdrawal(alice); + assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + + rollupMock.setBatchIndexes(3, 3); + vm.prank(alice); + submitter.claimWithdrawal(alice); + assertEq(submitter.stakeOf(alice), 0); + } + + function test_exitingStakeRemainsSlashable() public { + _registerAndStake(alice); + rollupMock.setBatchIndexes(2, 1); + vm.prank(alice); + submitter.withdraw(); + + uint256 rollupBalance = address(rollupMock).balance; + uint256 reward = rollupMock.slash(submitter, alice); + assertEq(reward, MINIMUM_STAKE / 4); + assertEq(address(rollupMock).balance - rollupBalance, reward); + assertEq(submitter.slashRemaining(), MINIMUM_STAKE - reward); + assertEq(submitter.stakeOf(alice), 0); + assertFalse(submitter.registered(alice)); + assertFalse(submitter.withdrawing(alice)); + + vm.prank(owner); + submitter.addSubmitter(alice); + vm.prank(alice); + submitter.stake{value: MINIMUM_STAKE}(); + assertTrue(submitter.isActive(alice)); + } + + function test_slashAccessZeroAddressAndRemainingClaim() public { + _registerAndStake(alice); + vm.prank(alice); + vm.expectRevert("only rollup contract"); + submitter.slash(alice); + + assertEq(rollupMock.slash(submitter, address(0)), 0); + rollupMock.slash(submitter, alice); + + uint256 beforeBalance = bob.balance; + vm.prank(owner); + submitter.claimSlashRemaining(bob); + assertEq(bob.balance - beforeBalance, (MINIMUM_STAKE * 75) / 100); + } + + function test_failedWithdrawalTransferPreservesStakeAndExit() public { + _registerAndStake(alice); + vm.prank(alice); + submitter.withdraw(); + RejectEther receiver = new RejectEther(); + + vm.prank(alice); + vm.expectRevert("ETH transfer failed"); + submitter.claimWithdrawal(address(receiver)); + assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + assertTrue(submitter.withdrawing(alice)); + } + + function _registerAndStake(address account) internal { + vm.prank(owner); + submitter.addSubmitter(account); + vm.prank(account); + submitter.stake{value: MINIMUM_STAKE}(); + } +} diff --git a/contracts/contracts/test/base/L1MessageBase.t.sol b/contracts/contracts/test/base/L1MessageBase.t.sol index d2fa9db4e..9e4f8acfe 100644 --- a/contracts/contracts/test/base/L1MessageBase.t.sol +++ b/contracts/contracts/test/base/L1MessageBase.t.sol @@ -7,7 +7,7 @@ import {CommonTest} from "./CommonTest.t.sol"; import {Whitelist} from "../../libraries/common/Whitelist.sol"; import {L1CrossDomainMessenger} from "../../l1/L1CrossDomainMessenger.sol"; import {L1MessageQueueWithGasPriceOracle} from "../../l1/rollup/L1MessageQueueWithGasPriceOracle.sol"; -import {L1Staking} from "../../l1/staking/L1Staking.sol"; +import {Submitter} from "../../l1/rollup/Submitter.sol"; import {Rollup} from "../../l1/rollup/Rollup.sol"; import {IRollup} from "../../l1/rollup/IRollup.sol"; import {BatchHeaderCodecV0} from "../../libraries/codec/BatchHeaderCodecV0.sol"; @@ -15,15 +15,12 @@ import {MockZkEvmVerifier} from "../../mock/MockZkEvmVerifier.sol"; contract L1MessageBaseTest is CommonTest { // Staking config - L1Staking public l1Staking; - L1Staking public l1StakingImpl; + Submitter public submitter; + Submitter public submitterImpl; uint256 public constant STAKING_VALUE = 1e18; // 1 eth uint256 public constant CHALLENGE_DEPOSIT = 1e18; // 1 eth - uint256 public constant LOCK_BLOCKS = 3; uint256 public rewardPercentage = 20; - uint32 public defaultGasLimitAdd = 1000000; - uint32 public defaultGasLimitRemove = 10000000; // Rollup config Rollup public rollup; @@ -92,6 +89,14 @@ contract L1MessageBaseTest is CommonTest { ); } + function _registerAndStakeSubmitter(address account) internal { + hevm.deal(account, 5 * STAKING_VALUE); + hevm.prank(multisig); + submitter.addSubmitter(account); + hevm.prank(account); + submitter.stake{value: STAKING_VALUE}(); + } + /// @dev Build V0 batch header for commitBatchWithProof (blob = ZERO_VERSIONED_HASH). function _createBatchHeaderV0ForProof( uint256 batchIndex, @@ -144,7 +149,7 @@ contract L1MessageBaseTest is CommonTest { address(multisig), new bytes(0) ); - TransparentUpgradeableProxy l1StakingProxy = new TransparentUpgradeableProxy( + TransparentUpgradeableProxy submitterProxy = new TransparentUpgradeableProxy( address(emptyContract), address(multisig), new bytes(0) @@ -158,7 +163,7 @@ contract L1MessageBaseTest is CommonTest { address(alice) ); l1CrossDomainMessengerImpl = new L1CrossDomainMessenger(); - l1StakingImpl = new L1Staking(payable(l1CrossDomainMessengerProxy)); + submitterImpl = new Submitter(); // upgrade and initialize ITransparentUpgradeableProxy(address(rollupProxy)).upgradeToAndCall( @@ -166,7 +171,7 @@ contract L1MessageBaseTest is CommonTest { abi.encodeCall( Rollup.initialize, ( - address(l1StakingProxy), + address(submitterProxy), address(l1MessageQueueWithGasPriceOracleProxy), // _messageQueue address(verifier), // _verifier finalizationPeriodSeconds, // _finalizationPeriodSeconds @@ -196,19 +201,11 @@ contract L1MessageBaseTest is CommonTest { ) ) ); - ITransparentUpgradeableProxy(address(l1StakingProxy)).upgradeToAndCall( - address(l1StakingImpl), + ITransparentUpgradeableProxy(address(submitterProxy)).upgradeToAndCall( + address(submitterImpl), abi.encodeCall( - L1Staking.initialize, - ( - address(rollupProxy), - STAKING_VALUE, - CHALLENGE_DEPOSIT, - LOCK_BLOCKS, - rewardPercentage, - defaultGasLimitAdd, - defaultGasLimitRemove - ) + Submitter.initialize, + (multisig, address(rollupProxy), STAKING_VALUE, CHALLENGE_DEPOSIT, rewardPercentage) ) ); @@ -217,9 +214,9 @@ contract L1MessageBaseTest is CommonTest { l1MessageQueueWithGasPriceOracle = L1MessageQueueWithGasPriceOracle( address(l1MessageQueueWithGasPriceOracleProxy) ); - l1Staking = L1Staking(address(l1StakingProxy)); + submitter = Submitter(payable(address(submitterProxy))); - _changeAdmin(address(l1Staking)); + _changeAdmin(address(submitter)); _changeAdmin(address(rollup)); _changeAdmin(address(l1CrossDomainMessenger)); _changeAdmin(address(l1MessageQueueWithGasPriceOracle)); From 5c0e78b43f49d457eb3f08e5b845eafafdc2c124 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 05:55:39 +0800 Subject: [PATCH 20/38] feat(node): decode submitter rollup selectors --- node/derivation/calldata_fixture_test.go | 135 ++++++++++++++++++ node/derivation/derivation.go | 88 +++++++----- node/derivation/derivation_test.go | 3 + .../testdata/rollup_calldata_fixtures.json | 93 ++++++++++++ node/types/batch.go | 7 + 5 files changed, 287 insertions(+), 39 deletions(-) create mode 100644 node/derivation/calldata_fixture_test.go create mode 100644 node/derivation/testdata/rollup_calldata_fixtures.json diff --git a/node/derivation/calldata_fixture_test.go b/node/derivation/calldata_fixture_test.go new file mode 100644 index 000000000..dc0083363 --- /dev/null +++ b/node/derivation/calldata_fixture_test.go @@ -0,0 +1,135 @@ +package derivation + +import ( + "encoding/json" + "errors" + "os" + "testing" + + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + "github.com/stretchr/testify/require" + + "morph-l2/bindings/bindings" + "morph-l2/node/types" +) + +type calldataFixtureCorpus struct { + SchemaVersion int `json:"schemaVersion"` + Fixtures []calldataFixture `json:"fixtures"` +} + +type calldataFixture struct { + Name string `json:"name"` + Selector string `json:"selector"` + Data string `json:"data"` + Expected calldataFixtureExpected `json:"expected"` +} + +type calldataFixtureExpected struct { + Version uint64 `json:"version"` + ParentBatchHeader string `json:"parentBatchHeader"` + BlockContexts string `json:"blockContexts"` + LastBlockNumber uint64 `json:"lastBlockNumber"` + NumL1Messages uint16 `json:"numL1Messages"` + PrevStateRoot string `json:"prevStateRoot"` + PostStateRoot string `json:"postStateRoot"` + WithdrawRoot string `json:"withdrawRoot"` +} + +func loadCalldataFixtureCorpus(t *testing.T) calldataFixtureCorpus { + t.Helper() + raw, err := os.ReadFile("testdata/rollup_calldata_fixtures.json") + require.NoError(t, err) + var corpus calldataFixtureCorpus + require.NoError(t, json.Unmarshal(raw, &corpus)) + require.Equal(t, 1, corpus.SchemaVersion) + require.Len(t, corpus.Fixtures, 6) + return corpus +} + +func newFixtureDerivation(t *testing.T) *Derivation { + t.Helper() + currentABI, err := bindings.RollupMetaData.GetAbi() + require.NoError(t, err) + preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) + legacyABI, err := types.LegacyRollupMetaData.GetAbi() + require.NoError(t, err) + beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() + require.NoError(t, err) + return &Derivation{ + rollupABI: currentABI, + preSubmitterRollupABI: preSubmitterABI, + legacyRollupABI: legacyABI, + beforeMoveBlockCtxABI: beforeMoveABI, + } +} + +func TestUnPackDataHistoricalAndCurrentSelectors(t *testing.T) { + d := newFixtureDerivation(t) + for _, fixture := range loadCalldataFixtureCorpus(t).Fixtures { + t.Run(fixture.Name, func(t *testing.T) { + data, err := hexutil.Decode(fixture.Data) + require.NoError(t, err) + require.Equal(t, fixture.Selector, hexutil.Encode(data[:4])) + + got, err := d.UnPackData(data) + require.NoError(t, err) + require.Equal(t, uint(fixture.Expected.Version), got.Version) + require.Equal(t, common.FromHex(fixture.Expected.ParentBatchHeader), []byte(got.ParentBatchHeader)) + expectedBlockContexts := fixture.Expected.BlockContexts + if expectedBlockContexts == "" { + expectedBlockContexts = "0x" + } + require.Equal(t, expectedBlockContexts, hexutil.Encode(got.BlockContexts)) + require.Equal(t, fixture.Expected.LastBlockNumber, got.LastBlockNumber) + require.Equal(t, fixture.Expected.NumL1Messages, got.NumL1Messages) + require.Equal(t, common.HexToHash(fixture.Expected.PrevStateRoot), got.PrevStateRoot) + require.Equal(t, common.HexToHash(fixture.Expected.PostStateRoot), got.PostStateRoot) + require.Equal(t, common.HexToHash(fixture.Expected.WithdrawRoot), got.WithdrawRoot) + }) + } +} + +func TestUnPackDataRejectsCommitStateUnknownShortAndMalformedCalldata(t *testing.T) { + d := newFixtureDerivation(t) + for _, input := range [][]byte{ + nil, + {0x01}, + {0x01, 0x02}, + {0x01, 0x02, 0x03}, + {0xde, 0xad, 0xbe, 0xef}, + {0x1e, 0x88, 0x25, 0xbe}, // pre-upgrade commitState + {0x67, 0xca, 0xa3, 0x7a}, // current commitState + } { + _, err := d.UnPackData(input) + require.ErrorIs(t, err, types.ErrNotCommitBatchTx) + } + + _, err := d.UnPackData([]byte{0x41, 0xf7, 0x56, 0xda}) + require.Error(t, err) + require.False(t, errors.Is(err, types.ErrNotCommitBatchTx), "a known selector with malformed arguments is not an unknown method") +} + +func TestRollupSelectorFreeze(t *testing.T) { + beforeMoveABI, err := types.BeforeMoveBlockCtxABI.GetAbi() + require.NoError(t, err) + legacyABI, err := types.LegacyRollupMetaData.GetAbi() + require.NoError(t, err) + preSubmitterABI, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) + currentABI, err := bindings.RollupMetaData.GetAbi() + require.NoError(t, err) + + require.Equal(t, "0x4a8d544f", hexutil.Encode(beforeMoveABI.Methods["commitBatch"].ID)) + require.Equal(t, "0xd63b3549", hexutil.Encode(legacyABI.Methods["commitBatch"].ID)) + require.Equal(t, "0x428868b5", hexutil.Encode(preSubmitterABI.Methods["commitBatch"].ID)) + require.Equal(t, "0x4e8f1d67", hexutil.Encode(preSubmitterABI.Methods["commitBatchWithProof"].ID)) + require.Equal(t, "0x41f756da", hexutil.Encode(currentABI.Methods["commitBatch"].ID)) + require.Equal(t, "0x1544ba3a", hexutil.Encode(currentABI.Methods["commitBatchWithProof"].ID)) + _, oldCommitStatePresent := preSubmitterABI.Methods["commitState"] + _, currentCommitStatePresent := currentABI.Methods["commitState"] + require.True(t, oldCommitStatePresent, "the archived full ABI still records historical commitState") + require.True(t, currentCommitStatePresent, "the full current ABI includes commitState") +} diff --git a/node/derivation/derivation.go b/node/derivation/derivation.go index b050f3483..00d9972aa 100644 --- a/node/derivation/derivation.go +++ b/node/derivation/derivation.go @@ -49,6 +49,7 @@ type Derivation struct { L2ToL1MessagePasser *bindings.L2ToL1MessagePasser rollupABI *abi.ABI + preSubmitterRollupABI *abi.ABI legacyRollupABI *abi.ABI // before remove skipMap beforeMoveBlockCtxABI *abi.ABI @@ -108,6 +109,10 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, if err != nil { return nil, err } + preSubmitterRollupAbi, err := types.PreSubmitterRollupMetaData.GetAbi() + if err != nil { + return nil, err + } legacyRollupAbi, err := types.LegacyRollupMetaData.GetAbi() if err != nil { return nil, err @@ -135,6 +140,7 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer, syncer: syncer, rollup: rollup, rollupABI: rollupAbi, + preSubmitterRollupABI: preSubmitterRollupAbi, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxAbi, logger: logger, @@ -605,6 +611,9 @@ func (d *Derivation) fetchRollupDataByTxHash(txHash common.Hash, blockNumber uin func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { var batch geth.RPCRollupBatch + if len(data) < 4 { + return batch, types.ErrNotCommitBatchTx + } if bytes.Equal(d.beforeMoveBlockCtxABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.beforeMoveBlockCtxABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { @@ -626,6 +635,7 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } + return batch, nil } else if bytes.Equal(d.legacyRollupABI.Methods["commitBatch"].ID, data[:4]) { args, err := d.legacyRollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) if err != nil { @@ -648,44 +658,46 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), } - } else if bytes.Equal(d.rollupABI.Methods["commitBatch"].ID, data[:4]) { - args, err := d.rollupABI.Methods["commitBatch"].Inputs.Unpack(data[4:]) - if err != nil { - return batch, fmt.Errorf("submitBatches Unpack error:%v", err) - } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - LastBlockNumber uint64 "json:\"lastBlockNumber\"" - NumL1Messages uint16 "json:\"numL1Messages\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) - batch = geth.RPCRollupBatch{ - Version: uint(rollupBatchData.Version), - ParentBatchHeader: rollupBatchData.ParentBatchHeader, - LastBlockNumber: rollupBatchData.LastBlockNumber, - NumL1Messages: rollupBatchData.NumL1Messages, - PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), - PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), - WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), + return batch, nil + } else if decoded, matched, err := unpackModernRollupCall(d.preSubmitterRollupABI, data); matched { + return decoded, err + } else if decoded, matched, err := unpackModernRollupCall(d.rollupABI, data); matched { + return decoded, err + } + return batch, types.ErrNotCommitBatchTx +} + +type modernBatchDataInput struct { + Version uint8 + ParentBatchHeader []byte + LastBlockNumber uint64 + NumL1Messages uint16 + PrevStateRoot [32]byte + PostStateRoot [32]byte + WithdrawalRoot [32]byte +} + +// unpackModernRollupCall intentionally recognizes only the two methods that +// derivation supported before this upgrade. commitState remains unsupported. +func unpackModernRollupCall(contractABI *abi.ABI, data []byte) (geth.RPCRollupBatch, bool, error) { + var batch geth.RPCRollupBatch + if contractABI == nil || len(data) < 4 { + return batch, false, nil + } + for _, methodName := range []string{"commitBatch", "commitBatchWithProof"} { + method, ok := contractABI.Methods[methodName] + if !ok || !bytes.Equal(method.ID, data[:4]) { + continue } - } else if bytes.Equal(d.rollupABI.Methods["commitBatchWithProof"].ID, data[:4]) { - args, err := d.rollupABI.Methods["commitBatchWithProof"].Inputs.Unpack(data[4:]) + args, err := method.Inputs.Unpack(data[4:]) if err != nil { - return batch, fmt.Errorf("commitBatchWithProof Unpack error:%v", err) + return batch, true, fmt.Errorf("%s Unpack error:%v", methodName, err) } - rollupBatchData := args[0].(struct { - Version uint8 "json:\"version\"" - ParentBatchHeader []uint8 "json:\"parentBatchHeader\"" - LastBlockNumber uint64 "json:\"lastBlockNumber\"" - NumL1Messages uint16 "json:\"numL1Messages\"" - PrevStateRoot [32]uint8 "json:\"prevStateRoot\"" - PostStateRoot [32]uint8 "json:\"postStateRoot\"" - WithdrawalRoot [32]uint8 "json:\"withdrawalRoot\"" - }) - batch = geth.RPCRollupBatch{ + if len(args) == 0 { + return batch, true, fmt.Errorf("%s has no batchDataInput", methodName) + } + rollupBatchData := *abi.ConvertType(args[0], new(modernBatchDataInput)).(*modernBatchDataInput) + return geth.RPCRollupBatch{ Version: uint(rollupBatchData.Version), ParentBatchHeader: rollupBatchData.ParentBatchHeader, LastBlockNumber: rollupBatchData.LastBlockNumber, @@ -693,11 +705,9 @@ func (d *Derivation) UnPackData(data []byte) (geth.RPCRollupBatch, error) { PrevStateRoot: common.BytesToHash(rollupBatchData.PrevStateRoot[:]), PostStateRoot: common.BytesToHash(rollupBatchData.PostStateRoot[:]), WithdrawRoot: common.BytesToHash(rollupBatchData.WithdrawalRoot[:]), - } - } else { - return batch, types.ErrNotCommitBatchTx + }, true, nil } - return batch, nil + return batch, false, nil } func (d *Derivation) parseBatch(batch geth.RPCRollupBatch) (*BatchInfo, error) { diff --git a/node/derivation/derivation_test.go b/node/derivation/derivation_test.go index 69eb750d6..be93f8dc5 100644 --- a/node/derivation/derivation_test.go +++ b/node/derivation/derivation_test.go @@ -19,12 +19,15 @@ var ( func TestUnPackData(t *testing.T) { rollupAbi, err := bindings.RollupMetaData.GetAbi() require.NoError(t, err) + preSubmitterRollupAbi, err := types.PreSubmitterRollupMetaData.GetAbi() + require.NoError(t, err) legacyRollupAbi, err := types.LegacyRollupMetaData.GetAbi() require.NoError(t, err) beforeMoveBlockCtxABI, err := types.BeforeMoveBlockCtxABI.GetAbi() require.NoError(t, err) d := Derivation{ rollupABI: rollupAbi, + preSubmitterRollupABI: preSubmitterRollupAbi, legacyRollupABI: legacyRollupAbi, beforeMoveBlockCtxABI: beforeMoveBlockCtxABI, } diff --git a/node/derivation/testdata/rollup_calldata_fixtures.json b/node/derivation/testdata/rollup_calldata_fixtures.json new file mode 100644 index 000000000..ca4f5f644 --- /dev/null +++ b/node/derivation/testdata/rollup_calldata_fixtures.json @@ -0,0 +1,93 @@ +{ + "schemaVersion": 1, + "fixtures": [ + { + "name": "before_move_commitBatch", + "epoch": "before-move", + "selector": "0x4a8d544f", + "data": "0x4a8d544f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 0, + "parentBatchHeader": "0x010203", + "blockContexts": "0xaabb", + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "legacy_commitBatch", + "epoch": "legacy", + "selector": "0xd63b3549", + "data": "0xd63b3549000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 1, + "parentBatchHeader": "0x010203", + "blockContexts": "0xaabb", + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "pre_submitter_commitBatch", + "epoch": "pre-submitter", + "selector": "0x428868b5", + "data": "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "pre_submitter_commitBatchWithProof", + "epoch": "pre-submitter", + "selector": "0x4e8f1d67", + "data": "0x4e8f1d67000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "current_commitBatch", + "epoch": "current", + "selector": "0x41f756da", + "data": "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + }, + { + "name": "current_commitBatchWithProof", + "epoch": "current", + "selector": "0x1544ba3a", + "data": "0x1544ba3a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025678000000000000000000000000000000000000000000000000000000000000", + "expected": { + "version": 2, + "parentBatchHeader": "0x010203", + "lastBlockNumber": 12345, + "numL1Messages": 7, + "prevStateRoot": "0x1111111111111111111111111111111111111111111111111111111111111111", + "postStateRoot": "0x2222222222222222222222222222222222222222222222222222222222222222", + "withdrawRoot": "0x3333333333333333333333333333333333333333333333333333333333333333" + } + } + ] +} diff --git a/node/types/batch.go b/node/types/batch.go index 3038dbb74..a3c3e3c6f 100644 --- a/node/types/batch.go +++ b/node/types/batch.go @@ -1,10 +1,17 @@ package types import ( + _ "embed" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" ) +//go:embed abi/pre_submitter_rollup.json +var preSubmitterRollupABI string + var ( + PreSubmitterRollupMetaData = &bind.MetaData{ABI: preSubmitterRollupABI} + LegacyRollupMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorIncorrectBatchLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrorNoBlockInBatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"blockContexts\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", } From ccb8cb2c9673c839b34d5c2831b72a5a9d906320 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 05:59:40 +0800 Subject: [PATCH 21/38] feat(prover): zero sequencer public input field --- prover/bin/challenge/src/abi/Rollup.json | 269 ++++++++++++++++-- prover/bin/challenge/src/abi/mod.rs | 88 ++++++ prover/bin/challenge/src/handler.rs | 26 +- prover/bin/server/src/queue.rs | 30 +- prover/bin/shadow-prove/abi/Rollup.json | 177 ++++++++---- prover/bin/shadow-prove/src/abi.rs | 74 ++++- prover/bin/shadow-prove/src/execute.rs | 2 - prover/bin/shadow-prove/src/shadow_rollup.rs | 51 +++- prover/crates/executor/client/src/lib.rs | 2 +- .../crates/executor/client/src/types/batch.rs | 59 ++-- .../client/src/verifier/evm_verifier.rs | 12 +- prover/crates/executor/host/src/execute.rs | 12 +- prover/crates/primitives/src/predeployed.rs | 6 - 13 files changed, 636 insertions(+), 172 deletions(-) diff --git a/prover/bin/challenge/src/abi/Rollup.json b/prover/bin/challenge/src/abi/Rollup.json index 28f7a5c6d..24828973e 100644 --- a/prover/bin/challenge/src/abi/Rollup.json +++ b/prover/bin/challenge/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -968,6 +1126,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1226,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1317,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index 5e88bf9fa..e905a2949 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -3,7 +3,95 @@ //! Contract ABIs are refactored into their own module to gracefully deal with allowing missing docs on the abigen macro. #![allow(missing_docs)] +use ethers::{abi::AbiDecode, contract::EthCall, types::Bytes}; +use eyre::{eyre, Result}; + pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } + +pub mod pre_submitter_rollup_abi { + use ethers::prelude::abigen; + abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CommitBatchInput { + pub version: u8, + pub parent_batch_header: Bytes, + pub last_block_number: u64, + pub num_l1_messages: u16, + pub prev_state_root: [u8; 32], + pub post_state_root: [u8; 32], + pub withdrawal_root: [u8; 32], +} + +macro_rules! commit_batch_input { + ($input:expr) => {{ + let input = $input; + CommitBatchInput { + version: input.version, + parent_batch_header: input.parent_batch_header, + last_block_number: input.last_block_number, + num_l1_messages: input.num_l1_messages, + prev_state_root: input.prev_state_root, + post_state_root: input.post_state_root, + withdrawal_root: input.withdrawal_root, + } + }}; +} + +/// Decode only the pre- or post-upgrade commitBatch method supported by challenge. +pub fn decode_commit_batch(data: &[u8]) -> Result { + use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; + use rollup_abi::CommitBatchCall; + + let selector = data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; + if selector == CommitBatchCall::selector() { + let call = CommitBatchCall::decode(data)?; + return Ok(commit_batch_input!(call.batch_data_input)); + } + if selector == PreSubmitterCommitBatchCall::selector() { + let call = PreSubmitterCommitBatchCall::decode(data)?; + return Ok(commit_batch_input!(call.batch_data_input)); + } + + Err(eyre!("unsupported rollup calldata selector")) +} + +#[cfg(test)] +mod tests { + use super::*; + use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; + use rollup_abi::CommitBatchCall; + + const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; + const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; + + fn calldata(value: &str) -> Vec { + ethers::utils::hex::decode(value.trim_start_matches("0x")).unwrap() + } + + #[test] + fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { + let pre = decode_commit_batch(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(); + let post = decode_commit_batch(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(); + + assert_eq!(pre, post); + assert_eq!(post.version, 2); + assert_eq!(post.last_block_number, 12_345); + assert_eq!(post.parent_batch_header.as_ref(), [1, 2, 3]); + assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); + assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); + } + + #[test] + fn rejects_non_commit_batch_calldata() { + assert!(decode_commit_batch(&[]).is_err()); + assert!(decode_commit_batch(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + assert!(decode_commit_batch(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); + assert!(decode_commit_batch(&[0x15, 0x44, 0xba, 0x3a]).is_err()); + assert!(decode_commit_batch(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); + } +} diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 36eac035f..b00daa729 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,13 +1,13 @@ -use crate::abi::rollup_abi::{CommitBatchCall, Rollup}; +use crate::abi::{decode_commit_batch, rollup_abi::Rollup}; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; +use ethers::prelude::*; use ethers::providers::{Http, Provider}; use ethers::signers::Wallet; use ethers::types::Address; use ethers::types::Bytes; -use ethers::{abi::AbiDecode, prelude::*}; use eyre::anyhow; use serde::{Deserialize, Serialize}; use std::env::var; @@ -449,21 +449,21 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let param = if let Ok(_param) = CommitBatchCall::decode(&data) { - _param + let input = if let Ok(input) = decode_commit_batch(&data) { + input } else { log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); return None; }; - let version: u8 = param.batch_data_input.version; - let prev_state_root: [u8; 32] = param.batch_data_input.prev_state_root; - let post_state_root: [u8; 32] = param.batch_data_input.post_state_root; - let withdrawal_root: [u8; 32] = param.batch_data_input.withdrawal_root; - let last_block_number: u64 = param.batch_data_input.last_block_number; - let num_l1_messages = param.batch_data_input.num_l1_messages; + let version = input.version; + let prev_state_root = input.prev_state_root; + let post_state_root = input.post_state_root; + let withdrawal_root = input.withdrawal_root; + let last_block_number = input.last_block_number; + let num_l1_messages = input.num_l1_messages; log::info!("======> batch inspect: decode tx.input, version = {:#?}", version); - log::info!("======> batch inspect: decode tx.input, param = {:#?}", param); + log::info!("======> batch inspect: decode tx.input, input = {:#?}", input); let mut batch_info = BatchInfo { version, @@ -477,7 +477,7 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat }; // prev_batch_header - let prev_batch_header: Bytes = param.batch_data_input.parent_batch_header; + let prev_batch_header = input.parent_batch_header; let prev_total_l1_message = prev_batch_header.get(17..25).unwrap_or_default(); let post_total_l1_message = u64::from_be_bytes(prev_total_l1_message.try_into().unwrap()) + batch_info.l1_message_popped; batch_info.total_l1_message_popped = post_total_l1_message; @@ -580,4 +580,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:?}", e) }; error_msg -} \ No newline at end of file +} diff --git a/prover/bin/server/src/queue.rs b/prover/bin/server/src/queue.rs index 219a50e69..b8ae27237 100644 --- a/prover/bin/server/src/queue.rs +++ b/prover/bin/server/src/queue.rs @@ -133,6 +133,13 @@ impl Prover { } } +fn encode_batch_header_data(data_hash: &[u8; 32], blob_input: &[u8; 32]) -> [u8; 96] { + let mut batch_header = [0u8; 96]; + batch_header[..32].copy_from_slice(data_hash); + batch_header[32..64].copy_from_slice(blob_input); + batch_header +} + /// Generate ExecutorInput for prover client. async fn gen_client_input( batch_index: u64, @@ -175,12 +182,9 @@ async fn gen_client_input( }; // Save batch_header_ex (uniform for all versions): // | data_hash(32) | blob_input(32) | seqSetVerifyHash(32) | (96 bytes) - let mut batch_header: Vec = Vec::with_capacity(96); - batch_header.extend_from_slice(&batch_info.data_hash().0); - batch_header.extend_from_slice(&blob_input.0); - batch_header.extend_from_slice(&batch_info.sequencer_root().0); + let batch_header = encode_batch_header_data(&batch_info.data_hash().0, &blob_input.0); let mut batch_file = File::create(proof_dir.join("batch_header.data"))?; - batch_file.write_all(&batch_header[..]).expect("failed to batch_header"); + batch_file.write_all(&batch_header).expect("failed to batch_header"); } else { let err = verify_result.unwrap_err(); let error_data = serde_json::json!({ @@ -226,3 +230,19 @@ fn save_trace(batch_index: u64, chunk_traces: &Vec) { serde_json::to_writer_pretty(writer, &chunk_traces).unwrap(); log::info!("chunk_traces of batch_index = {:#?} saved", batch_index); } + +#[cfg(test)] +mod tests { + use super::encode_batch_header_data; + + #[test] + fn batch_header_data_keeps_96_bytes_and_zeroes_the_third_field() { + let data_hash = [0x11; 32]; + let blob_input = [0x22; 32]; + let encoded = encode_batch_header_data(&data_hash, &blob_input); + + assert_eq!(&encoded[..32], &data_hash); + assert_eq!(&encoded[32..64], &blob_input); + assert_eq!(&encoded[64..], &[0u8; 32]); + } +} diff --git a/prover/bin/shadow-prove/abi/Rollup.json b/prover/bin/shadow-prove/abi/Rollup.json index e32ca8619..24828973e 100644 --- a/prover/bin/shadow-prove/abi/Rollup.json +++ b/prover/bin/shadow-prove/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -383,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -460,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -656,28 +694,6 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" } ], "name": "commitBatch", @@ -729,40 +745,68 @@ "name": "batchDataInput", "type": "tuple" }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, { - "internalType": "bytes", - "name": "signature", - "type": "bytes" + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" } ], - "name": "commitBatchWithProof", + "name": "commitState", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -880,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -940,6 +984,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -978,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1208,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1322,4 +1379,4 @@ "stateMutability": "payable", "type": "receive" } -] \ No newline at end of file +] diff --git a/prover/bin/shadow-prove/src/abi.rs b/prover/bin/shadow-prove/src/abi.rs index d98d7b99d..6d07b05c8 100644 --- a/prover/bin/shadow-prove/src/abi.rs +++ b/prover/bin/shadow-prove/src/abi.rs @@ -1,4 +1,6 @@ -use alloy_sol_types::sol; +use alloy_primitives::Bytes; +use alloy_sol_types::{sol, SolCall}; +use anyhow::{anyhow, Result}; // Codegen from ABI file to interact with the contract. sol!( @@ -7,6 +9,43 @@ sol!( "abi/Rollup.json" ); +// Immutable Rollup ABI from immediately before BatchSignatureInput was removed. +pub mod pre_submitter { + use alloy_sol_types::sol; + + sol!(PreSubmitterRollup, "abi/pre_submitter/Rollup.json"); +} +use pre_submitter::PreSubmitterRollup; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CommitBatchInput { + pub parent_batch_header: Bytes, + pub last_block_number: u64, +} + +/// Decode the pre- or post-upgrade commitBatch calldata handled by shadow-prove. +pub fn decode_commit_batch(data: &[u8]) -> Result { + let selector = + data.get(..4).ok_or_else(|| anyhow!("rollup calldata is shorter than a selector"))?; + + if selector == Rollup::commitBatchCall::SELECTOR { + let call = Rollup::commitBatchCall::abi_decode(data)?; + return Ok(CommitBatchInput { + parent_batch_header: call.batchDataInput.parentBatchHeader, + last_block_number: call.batchDataInput.lastBlockNumber, + }); + } + if selector == PreSubmitterRollup::commitBatchCall::SELECTOR { + let call = PreSubmitterRollup::commitBatchCall::abi_decode(data)?; + return Ok(CommitBatchInput { + parent_batch_header: call.batchDataInput.parentBatchHeader, + last_block_number: call.batchDataInput.lastBlockNumber, + }); + } + + Err(anyhow!("unsupported rollup calldata selector")) +} + sol!( #[sol(rpc)] ShadowRollup, @@ -18,3 +57,36 @@ sol!( SP1Verifier, "abi/SP1Verifier.json" ); + +#[cfg(test)] +mod tests { + use super::*; + + const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; + const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; + + fn calldata(value: &str) -> Vec { + alloy_primitives::hex::decode(value.trim_start_matches("0x")).unwrap() + } + + #[test] + fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { + let pre = decode_commit_batch(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(); + let post = decode_commit_batch(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(); + + assert_eq!(pre, post); + assert_eq!(post.last_block_number, 12_345); + assert_eq!(post.parent_batch_header.as_ref(), [1, 2, 3]); + assert_eq!(Rollup::commitBatchCall::SELECTOR, [0x41, 0xf7, 0x56, 0xda]); + assert_eq!(PreSubmitterRollup::commitBatchCall::SELECTOR, [0x42, 0x88, 0x68, 0xb5]); + } + + #[test] + fn rejects_non_commit_batch_calldata() { + assert!(decode_commit_batch(&[]).is_err()); + assert!(decode_commit_batch(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + assert!(decode_commit_batch(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); + assert!(decode_commit_batch(&[0x15, 0x44, 0xba, 0x3a]).is_err()); + assert!(decode_commit_batch(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); + } +} diff --git a/prover/bin/shadow-prove/src/execute.rs b/prover/bin/shadow-prove/src/execute.rs index 1a5142e6e..4792c1fe0 100644 --- a/prover/bin/shadow-prove/src/execute.rs +++ b/prover/bin/shadow-prove/src/execute.rs @@ -252,7 +252,6 @@ mod tests { &inputs, B256::default(), B256::default(), - B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); @@ -268,7 +267,6 @@ mod tests { &inputs, B256::default(), B256::default(), - B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index df1f7292c..b70610623 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -1,11 +1,9 @@ -use crate::{metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; +use crate::{abi::decode_commit_batch, metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; use alloy_consensus::Transaction; use alloy_network::{Network, ReceiptResponse}; use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256, U64}; use alloy_provider::{DynProvider, Provider}; use alloy_rpc_types::Log; -use alloy_sol_types::SolCall; - use anyhow::{anyhow, Context, Result}; use futures::future::join_all; @@ -14,6 +12,34 @@ use crate::{ ShadowRollup::{self, ShadowRollupInstance}, }; +fn sequencer_set_verify_hash(batch_header: &Bytes) -> Result { + let field: [u8; 32] = batch_header + .get(185..217) + .ok_or_else(|| anyhow!("batch header is shorter than the sequencerSetVerifyHash field"))? + .try_into() + .map_err(|_| anyhow!("invalid sequencerSetVerifyHash field length"))?; + if field != [0u8; 32] { + return Err(anyhow!("sequencerSetVerifyHash must be zero after the upgrade")); + } + Ok(B256::from(field)) +} + +#[cfg(test)] +mod header_field_tests { + use super::*; + + #[test] + fn post_upgrade_header_keeps_the_field_at_185_and_requires_zero() { + let mut header = vec![0x11; 249]; + header[185..217].fill(0); + assert_eq!(sequencer_set_verify_hash(&Bytes::from(header.clone())).unwrap(), B256::ZERO); + + header[216] = 1; + assert!(sequencer_set_verify_hash(&Bytes::from(header)).is_err()); + assert!(sequencer_set_verify_hash(&Bytes::from(vec![0u8; 216])).is_err()); + } +} + #[derive(Clone, Debug)] pub struct BatchSyncer { l1_provider: DynProvider, @@ -337,6 +363,7 @@ where // @dev Below is the feilds for `BatchHeader` V1 // * lastBlockNumber 8 uint64 249 The last block number in this batch // ``` + let sequencer_set_verify_hash = sequencer_set_verify_hash(&batch_header)?; let batch_store = ShadowRollup::BatchStore { prevStateRoot: batch_header .get(89..121) @@ -359,11 +386,7 @@ where .unwrap_or_default() .try_into() .unwrap_or_default(), - sequencerSetVerifyHash: batch_header - .get(185..217) - .unwrap_or_default() - .try_into() - .unwrap_or_default(), + sequencerSetVerifyHash: sequencer_set_verify_hash, }; // Commit the shadow batch. @@ -459,7 +482,7 @@ where let post_state_root: &[u8] = batch_header.get(121..153).unwrap_or_default(); let withdrawal_root: &[u8] = batch_header.get(153..185).unwrap_or_default(); let data_hash: &[u8] = batch_header.get(25..57).unwrap_or_default(); - let sequencer_set_verify_hash: &[u8] = batch_header.get(185..217).unwrap_or_default(); + let sequencer_set_verify_hash = sequencer_set_verify_hash(batch_header)?; // All versions: blob input at offset 57 (aggregated hash for V2, versioned hash for V0/V1) let blob_input: &[u8] = batch_header.get(57..89).unwrap_or_default(); @@ -480,7 +503,7 @@ where hasher.update(prev_state_root); hasher.update(post_state_root); hasher.update(withdrawal_root); - hasher.update(sequencer_set_verify_hash); + hasher.update(sequencer_set_verify_hash.as_slice()); hasher.update(data_hash); hasher.update(blob_input); Ok(hasher.finalize()) @@ -509,15 +532,13 @@ pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Opt log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let param = if let Ok(_param) = Rollup::commitBatchCall::abi_decode(data) { - _param + let input = if let Ok(input) = decode_commit_batch(data) { + input } else { log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); return None; }; - let parent_batch_header: Bytes = param.batchDataInput.parentBatchHeader; - let last_block_number: u64 = param.batchDataInput.lastBlockNumber; - Some((parent_batch_header, last_block_number)) + Some((input.parent_batch_header, input.last_block_number)) } #[tokio::test] async fn test_sync_batch() { diff --git a/prover/crates/executor/client/src/lib.rs b/prover/crates/executor/client/src/lib.rs index 7524e1e6f..285cf1638 100644 --- a/prover/crates/executor/client/src/lib.rs +++ b/prover/crates/executor/client/src/lib.rs @@ -31,7 +31,7 @@ pub fn verify(input: ExecutorInput) -> Result { hex::encode(batch_info.withdraw_root().as_slice()), hex::encode(batch_info.data_hash().as_slice()), versioned_hashes.iter().map(|h| hex::encode(h.as_slice())).collect::>(), - hex::encode(batch_info.sequencer_root().as_slice()), + hex::encode(B256::ZERO.as_slice()), input.batch_version, ); let public_input_hash = match input.batch_version { diff --git a/prover/crates/executor/client/src/types/batch.rs b/prover/crates/executor/client/src/types/batch.rs index 5cb7b7c9a..9334cfbea 100644 --- a/prover/crates/executor/client/src/types/batch.rs +++ b/prover/crates/executor/client/src/types/batch.rs @@ -16,8 +16,6 @@ pub struct BatchInfo { pub post_state_root: B256, /// withdraw_root pub withdraw_root: Option, - /// sequencer_root - pub sequencer_root: Option, data_hash: B256, } @@ -27,7 +25,6 @@ impl BatchInfo { block_inputs: &[BlockInput], post_state_root: B256, withdraw_root: B256, - sequencer_root: B256, ) -> Self { let blocks = block_inputs.iter().map(|x| x.current_block.clone()).collect::>(); let chain_id = blocks.first().unwrap().chain_id; @@ -48,7 +45,6 @@ impl BatchInfo { prev_state_root, post_state_root, withdraw_root: Some(withdraw_root), - sequencer_root: Some(sequencer_root), data_hash: l1_data_hash, } } @@ -59,20 +55,24 @@ impl BatchInfo { /// prev state root || /// post state root || /// withdraw root || - /// sequencer root || + /// bytes32(0) || /// txdata hash || /// blob versioned hash /// ) pub fn public_input_hash(&self, versioned_hash: &B256) -> B256 { + self.public_input_hash_with_blob_input(versioned_hash) + } + + fn public_input_hash_with_blob_input(&self, blob_input: &B256) -> B256 { let mut hasher = Keccak256::new(); hasher.update(self.chain_id.to_be_bytes()); hasher.update(self.prev_state_root.as_slice()); hasher.update(self.post_state_root.as_slice()); hasher.update(self.withdraw_root.unwrap().as_slice()); - hasher.update(self.sequencer_root.unwrap().as_slice()); + hasher.update(B256::ZERO.as_slice()); hasher.update(self.data_hash.as_slice()); - hasher.update(versioned_hash.as_slice()); + hasher.update(blob_input.as_slice()); hasher.finalize() } @@ -85,15 +85,7 @@ impl BatchInfo { } let blob_hashes_hash: B256 = blob_hasher.finalize(); - let mut hasher = Keccak256::new(); - hasher.update(self.chain_id.to_be_bytes()); - hasher.update(self.prev_state_root.as_slice()); - hasher.update(self.post_state_root.as_slice()); - hasher.update(self.withdraw_root.unwrap().as_slice()); - hasher.update(self.sequencer_root.unwrap().as_slice()); - hasher.update(self.data_hash.as_slice()); - hasher.update(blob_hashes_hash.as_slice()); - hasher.finalize() + self.public_input_hash_with_blob_input(&blob_hashes_hash) } /// Chain ID of this chunk @@ -108,7 +100,6 @@ impl BatchInfo { prev_state_root: B256::ZERO, post_state_root: B256::ZERO, withdraw_root: Some(B256::ZERO), - sequencer_root: Some(B256::ZERO), data_hash: B256::ZERO, } } @@ -128,11 +119,6 @@ impl BatchInfo { self.withdraw_root.expect("get withdraw_root") } - /// Sequencer root after this chunk - pub fn sequencer_root(&self) -> B256 { - self.sequencer_root.expect("get sequencer_root") - } - /// Data hash of this chunk pub fn data_hash(&self) -> B256 { self.data_hash @@ -153,6 +139,33 @@ mod tests { B256::from(b) } + #[test] + fn public_input_hash_keeps_the_32_byte_field_and_sets_it_to_zero() { + let batch = BatchInfo { + chain_id: TEST_CHAIN_ID, + prev_state_root: make_hash(1), + post_state_root: make_hash(2), + withdraw_root: Some(make_hash(3)), + data_hash: make_hash(4), + }; + let blob_input = make_hash(5); + + let mut preimage = Vec::with_capacity(200); + preimage.extend_from_slice(&TEST_CHAIN_ID.to_be_bytes()); + preimage.extend_from_slice(batch.prev_state_root.as_slice()); + preimage.extend_from_slice(batch.post_state_root.as_slice()); + preimage.extend_from_slice(batch.withdraw_root().as_slice()); + preimage.extend_from_slice(B256::ZERO.as_slice()); + preimage.extend_from_slice(batch.data_hash().as_slice()); + preimage.extend_from_slice(blob_input.as_slice()); + + assert_eq!(preimage.len(), 200); + assert_eq!(batch.public_input_hash(&blob_input), keccak256(&preimage)); + + preimage[104..136].copy_from_slice(make_hash(99).as_slice()); + assert_ne!(batch.public_input_hash(&blob_input), keccak256(&preimage)); + } + /// V2 aggregated hash for a single blob: keccak256(h0) != h0 (not backward-compatible with V1). #[test] fn test_public_input_hash_v2_single_blob_differs_from_v1() { @@ -184,7 +197,7 @@ mod tests { hasher.update(B256::ZERO.as_slice()); // prev_state_root hasher.update(B256::ZERO.as_slice()); // post_state_root hasher.update(B256::ZERO.as_slice()); // withdraw_root - hasher.update(B256::ZERO.as_slice()); // sequencer_root + hasher.update(B256::ZERO.as_slice()); // reserved zero field hasher.update(B256::ZERO.as_slice()); // data_hash hasher.update(aggregated.as_slice()); let expected: B256 = hasher.finalize(); diff --git a/prover/crates/executor/client/src/verifier/evm_verifier.rs b/prover/crates/executor/client/src/verifier/evm_verifier.rs index e35083bc7..946129a52 100644 --- a/prover/crates/executor/client/src/verifier/evm_verifier.rs +++ b/prover/crates/executor/client/src/verifier/evm_verifier.rs @@ -2,9 +2,7 @@ use crate::types::batch::BatchInfo; use crate::types::error::ClientError; use crate::types::input::BlockInput; use prover_executor_core::MorphExecutor; -use prover_primitives::predeployed::l2_to_l1_message::{ - SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, -}; +use prover_primitives::predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}; use reth_trie::{HashedPostState, KeccakKeyHasher}; use revm::context::BlockEnv; use revm::database::State; @@ -46,18 +44,16 @@ fn execute(mut block_inputs: Vec) -> Result } } - // The post-withdraw-root & post-sequencer-root is required for public inputs. - // Tt is derived from the state of the last verified block. + // The withdrawal root is derived from the state of the last verified block. + // The former sequencer-root public-input field is now a fixed zero and does + // not require a dedicated storage witness. let post_withdraw_root = latest_block.get_storage_value(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT)?; - let post_sequencer_root = - latest_block.get_storage_value(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT)?; Ok(BatchInfo::from_block_inputs( &block_inputs, latest_block.current_block.post_state_root, post_withdraw_root.into(), - post_sequencer_root.into(), )) } diff --git a/prover/crates/executor/host/src/execute.rs b/prover/crates/executor/host/src/execute.rs index 10dd2ac31..b4cb4ba68 100644 --- a/prover/crates/executor/host/src/execute.rs +++ b/prover/crates/executor/host/src/execute.rs @@ -3,9 +3,7 @@ use alloy_provider::{DynProvider, Provider}; use anyhow::{bail, Context}; use prover_executor_core::MorphExecutor; use prover_primitives::{ - predeployed::l2_to_l1_message::{ - SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, - }, + predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}, TxTrace, }; use prover_storage_rpc::basic_rpc_db::{BasicRpcDb, RpcDb}; @@ -136,14 +134,6 @@ async fn load_predeployed_contracts( .fetch_storage_at(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT) .await .context("failed to fetch WITHDRAW_ROOT_ADDRESS storage slot")?; - rpc_db - .fetch_account_info(SEQUENCER_ROOT_ADDRESS) - .await - .context("failed to fetch SEQUENCER_ROOT_ADDRESS account info")?; - rpc_db - .fetch_storage_at(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT) - .await - .context("failed to fetch SEQUENCER_ROOT_ADDRESS storage slot")?; Ok(()) } diff --git a/prover/crates/primitives/src/predeployed.rs b/prover/crates/primitives/src/predeployed.rs index fe42ed8c6..dd5800071 100644 --- a/prover/crates/primitives/src/predeployed.rs +++ b/prover/crates/primitives/src/predeployed.rs @@ -37,10 +37,4 @@ pub mod l2_to_l1_message { address!("0x5300000000000000000000000000000000000001"); /// Withdraw root slot pub const WITHDRAW_ROOT_SLOT: U256 = uint!(33_U256); - - /// Sequencer root address - pub const SEQUENCER_ROOT_ADDRESS: Address = - address!("0x5300000000000000000000000000000000000017"); - /// Sequencer root slot - pub const SEQUENCER_ROOT_SLOT: U256 = uint!(101_U256); } From 455d9ffbcd4cb643d65fabd4379d7b57fefe1795 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:00:30 +0800 Subject: [PATCH 22/38] feat(gas-oracle): support submitter rollup calldata --- gas-oracle/app/src/abi/Rollup.json | 269 +++++++++++++++++++--- gas-oracle/app/src/abi/mod.rs | 62 +++++ gas-oracle/app/src/da_scalar/l1_scalar.rs | 13 +- 3 files changed, 311 insertions(+), 33 deletions(-) diff --git a/gas-oracle/app/src/abi/Rollup.json b/gas-oracle/app/src/abi/Rollup.json index 28f7a5c6d..24828973e 100644 --- a/gas-oracle/app/src/abi/Rollup.json +++ b/gas-oracle/app/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -968,6 +1126,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1226,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1317,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/gas-oracle/app/src/abi/mod.rs b/gas-oracle/app/src/abi/mod.rs index fdcc9a2c2..77ec97a97 100644 --- a/gas-oracle/app/src/abi/mod.rs +++ b/gas-oracle/app/src/abi/mod.rs @@ -4,6 +4,9 @@ //! on the abigen macro. #![allow(missing_docs)] +use ethers::{abi::AbiDecode, contract::EthCall}; +use eyre::{eyre, Result}; + pub mod gas_price_oracle_abi { use ethers::prelude::abigen; abigen!(GasPriceOracle, "src/abi/GasPriceOracle.json"); @@ -13,3 +16,62 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } + +pub mod pre_submitter_rollup_abi { + use ethers::prelude::abigen; + abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); +} + +/// Decode the last block number from the pre- or post-upgrade commitBatch calldata. +pub fn decode_commit_batch_last_block_number(data: &[u8]) -> Result { + use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; + use rollup_abi::CommitBatchCall; + + let selector = + data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; + if selector == CommitBatchCall::selector() { + return Ok(CommitBatchCall::decode(data)?.batch_data_input.last_block_number); + } + if selector == PreSubmitterCommitBatchCall::selector() { + return Ok(PreSubmitterCommitBatchCall::decode(data)?.batch_data_input.last_block_number); + } + + Err(eyre!("unsupported rollup calldata selector")) +} + +#[cfg(test)] +mod tests { + use super::*; + use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; + use rollup_abi::CommitBatchCall; + + const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; + const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; + + fn calldata(value: &str) -> Vec { + ethers::utils::hex::decode(value.trim_start_matches("0x")).unwrap() + } + + #[test] + fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { + assert_eq!( + decode_commit_batch_last_block_number(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(), + 12_345 + ); + assert_eq!( + decode_commit_batch_last_block_number(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(), + 12_345 + ); + assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); + assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); + } + + #[test] + fn rejects_non_commit_batch_calldata() { + assert!(decode_commit_batch_last_block_number(&[]).is_err()); + assert!(decode_commit_batch_last_block_number(&[0xde, 0xad, 0xbe, 0xef]).is_err()); + assert!(decode_commit_batch_last_block_number(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); + assert!(decode_commit_batch_last_block_number(&[0x15, 0x44, 0xba, 0x3a]).is_err()); + assert!(decode_commit_batch_last_block_number(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); + } +} diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index bbd6d8e7a..f10928cdb 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -11,13 +11,13 @@ use super::{ }; use crate::{ abi::{ - gas_price_oracle_abi::GasPriceOracle, - rollup_abi::{CommitBatchCall, Rollup}, + decode_commit_batch_last_block_number, gas_price_oracle_abi::GasPriceOracle, + rollup_abi::Rollup, }, metrics::ORACLE_SERVICE_METRICS, signer::send_transaction, }; -use ethers::{abi::AbiDecode, prelude::*, utils::hex}; +use ethers::{prelude::*, utils::hex}; use remote_signer_client::SignerClient; use serde_json::Value; @@ -341,13 +341,14 @@ impl ScalarUpdater { log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", tx_hash); return Err(ScalarError::Error(anyhow!(format!("commitBatch tx.input empty")))); } - let param = if let Ok(_param) = CommitBatchCall::decode(&blob_tx.input) { - _param + let last_block_num = if let Ok(last_block_num) = + decode_commit_batch_last_block_number(&blob_tx.input) + { + last_block_num } else { log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); return Err(ScalarError::Error(anyhow!(format!("decode commitBatch tx.input error",)))); }; - let last_block_num: u64 = param.batch_data_input.last_block_number; let indexes: Vec = indexed_hashes.iter().map(|item| item.index).collect(); let sidecars_rt = self From 51b74bdccd1bad3cdc7d764245b2787e29a5aee0 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:02:45 +0800 Subject: [PATCH 23/38] feat(deploy): wire submitter contracts and bindings --- bindings/Makefile | 11 +- bindings/bin/l1staking_deployed.hex | 1 - bindings/bin/rollup_deployed.hex | 2 +- bindings/bin/submitter_deployed.hex | 1 + .../bindings/centralization_cleanup_test.go | 99 + bindings/bindings/l1staking.go | 3445 ----------------- bindings/bindings/l1staking_more.go | 25 - bindings/bindings/rollup.go | 377 +- bindings/bindings/rollup_more.go | 4 +- bindings/bindings/submitter.go | 2502 ++++++++++++ bindings/bindings/submitter_more.go | 25 + contracts/deploy/013-DeployProxys.ts | 12 +- contracts/deploy/014-DeployImpls.ts | 44 +- contracts/deploy/015-SubmitterInit.ts | 78 + contracts/deploy/016-RollupInit.ts | 10 +- contracts/deploy/018-StakingInit.ts | 128 - contracts/deploy/019-AdminTransfer.ts | 12 +- contracts/deploy/020-ContractInit.ts | 44 +- contracts/deploy/021-StakingRegister.ts | 57 - contracts/deploy/021-SubmitterRegister.ts | 45 + contracts/deploy/index.ts | 10 +- contracts/hardhat.config.ts | 7 +- contracts/package.json | 3 +- contracts/scripts/clean-generated-abi.js | 16 + contracts/scripts/verify-abi-archive.js | 36 + contracts/src/deploy-config/holesky.ts | 17 +- contracts/src/deploy-config/hoodi.ts | 17 +- contracts/src/deploy-config/l1.ts | 17 +- contracts/src/deploy-config/qanetl1.ts | 17 +- contracts/src/deploy-config/sepolia.ts | 9 +- contracts/src/deploy-config/testnetl1.ts | 9 +- contracts/src/types.ts | 14 +- contracts/tasks/README.md | 13 + contracts/tasks/deploy.ts | 57 +- contracts/tasks/proxy_upgrade.ts | 62 +- contracts/tasks/staking_upgrade.ts | 901 ----- 36 files changed, 3250 insertions(+), 4877 deletions(-) delete mode 100644 bindings/bin/l1staking_deployed.hex create mode 100644 bindings/bin/submitter_deployed.hex create mode 100644 bindings/bindings/centralization_cleanup_test.go delete mode 100644 bindings/bindings/l1staking.go delete mode 100644 bindings/bindings/l1staking_more.go create mode 100644 bindings/bindings/submitter.go create mode 100644 bindings/bindings/submitter_more.go create mode 100644 contracts/deploy/015-SubmitterInit.ts delete mode 100644 contracts/deploy/018-StakingInit.ts delete mode 100644 contracts/deploy/021-StakingRegister.ts create mode 100644 contracts/deploy/021-SubmitterRegister.ts create mode 100644 contracts/scripts/clean-generated-abi.js create mode 100644 contracts/scripts/verify-abi-archive.js delete mode 100644 contracts/tasks/staking_upgrade.ts diff --git a/bindings/Makefile b/bindings/Makefile index a98e10d37..616ebf372 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -5,7 +5,7 @@ pkg := bindings all: version mkdir bindings more bindings: \ - l1-staking-bindings \ + submitter-bindings \ l1-cross-domain-messenger-bindings \ l1-standard-erc20-gateway-bindings \ l1-eth-gateway-bindings \ @@ -65,9 +65,9 @@ compile-forge: ./compile.sh forge ## L1 -# Staking -l1-staking-bindings: compile - ./gen_bindings.sh contracts/l1/staking/L1Staking.sol:L1Staking $(pkg) +# Submitter +submitter-bindings: compile + ./gen_bindings.sh contracts/l1/rollup/Submitter.sol:Submitter $(pkg) # CrossDomainMessenger l1-cross-domain-messenger-bindings: compile @@ -194,7 +194,7 @@ more: compile-forge go run ./gen/main.go \ -artifacts ../contracts/artifacts \ -out ./bindings \ - -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,L1Staking,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ + -contracts ProxyAdmin,TransparentUpgradeableProxy,L2TokenRegistry,L1MessageQueueWithGasPriceOracle,L1USDCGateway,Submitter,L1CrossDomainMessenger,L1StandardERC20Gateway,L1ETHGateway,L1ERC20Gateway,L1GatewayRouter,L1WETHGateway,L1LidoGateway,Rollup,MultipleVersionRollupVerifier,L2CrossDomainMessenger,GasPriceOracle,L2ToL1MessagePasser,L2TxFeeVault,Sequencer,Gov,Distribute,L2Staking,Record,L2ETHGateway,L2StandardERC20Gateway,L2GatewayRouter,L2WETHGateway,L2ERC20Gateway,L2ERC721Gateway,L2ERC1155Gateway,L2LidoGateway,MorphToken,MorphStandardERC20,MorphStandardERC20Factory,WrappedEther,L2USDCGateway,EnforcedTxGateway,L1ERC721Gateway,L1ERC1155Gateway,L1ReverseCustomGateway,L2WithdrawLockERC20Gateway,L2ReverseCustomGateway,Whitelist,ZkEvmVerifierV1,L2WstETHToken \ -package bindings mkdir: @@ -211,4 +211,3 @@ test: lint: GOBIN=$(PWD)/build/bin go run ../build/lint.go .PHONY: lint - diff --git a/bindings/bin/l1staking_deployed.hex b/bindings/bin/l1staking_deployed.hex deleted file mode 100644 index 401476f33..000000000 --- a/bindings/bin/l1staking_deployed.hex +++ /dev/null @@ -1 +0,0 @@ -0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bin/rollup_deployed.hex b/bindings/bin/rollup_deployed.hex index 68a52ca9c..4f4b9da32 100644 --- a/bindings/bin/rollup_deployed.hex +++ b/bindings/bin/rollup_deployed.hex @@ -1 +1 @@ -0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a +0x60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610af6578063f2fde38b14610b15578063f8fa010f14610b34578063fb1e8b0414610b53575f80fd5b8063d8dc99d214610aad578063de8b303514610ac2578063dff7827e14610ae1575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a47578063ce5db8d614610a5a578063cf9a674514610a6f578063d279c19114610a8e575f80fd5b8063b8d0a1b0146109ea578063bedb86fb14610a09578063c555389214610a28575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d314610978578063b34844251461098d578063b35dac4e146109ac578063b3e0a509146109cb575f80fd5b8063a479265d14610919578063a4f209b01461092e578063abc8d68d1461094d575f80fd5b8063910129d411610198578063910129d41461087c57806397fc007c146108ad578063a3c9e94c146108cc578063a415d8dc146108eb575f80fd5b806388b1ea09146107965780638da5cb5b146107af5780638f1d3776146107cc575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa146107195780636c578c1d14610744578063715018a614610763578063728cdbca14610777575f80fd5b80635f77cf1d1461068f57806361267290146106db57806367caa37a146106fa575f80fd5b806341f756da1161026e57806341f756da146105d457806357e0af6c146105e75780635c975abb146106065780635ef7a94a1461061d575f80fd5b80632b7ac3f3146105695780633b70c18a146105a05780633e001b66146105bf575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004614ed4565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004614f01565b610b68565b005b3480156103fb575f80fd5b506103ee61040a366004614f5f565b610c3a565b34801561041a575f80fd5b50610397610429366004614ed4565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004614fa7565b610f76565b348015610470575f80fd5b506103ee61047f366004614ff6565b611493565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004614ed4565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004614ed4565b611852565b3480156104f3575f80fd5b506103c1610502366004614ed4565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004614ed4565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004614ed4565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c54610588906001600160a01b031681565b6040516001600160a01b0390911681526020016103a3565b3480156105ab575f80fd5b50609b54610588906001600160a01b031681565b3480156105ca575f80fd5b506103c160aa5481565b6103ee6105e2366004615084565b611880565b3480156105f2575f80fd5b506103ee610601366004614ed4565b611b84565b348015610611575f80fd5b5060655460ff16610397565b348015610628575f80fd5b50610666610637366004614ed4565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103a3565b34801561069a575f80fd5b506106c27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b3480156106e6575f80fd5b506103ee6106f5366004614ed4565b611c2f565b348015610705575f80fd5b506103ee610714366004615084565b611e0a565b348015610724575f80fd5b506103c1610733366004614ed4565b60ab6020525f908152604090205481565b34801561074f575f80fd5b506103ee61075e366004614f01565b612155565b34801561076e575f80fd5b506103ee612212565b348015610782575f80fd5b506103ee6107913660046150be565b612225565b3480156107a1575f80fd5b5060a6546103979060ff1681565b3480156107ba575f80fd5b506033546001600160a01b0316610588565b3480156107d7575f80fd5b506108386107e6366004614ed4565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b348015610887575f80fd5b50610397610896366004614ed4565b5f90815260a4602052604090206003015460ff1690565b3480156108b8575f80fd5b506103ee6108c7366004614f01565b61252e565b3480156108d7575f80fd5b50609754610588906001600160a01b031681565b3480156108f6575f80fd5b50610397610905366004614f01565b609f6020525f908152604090205460ff1681565b348015610924575f80fd5b506103c160995481565b348015610939575f80fd5b506103ee610948366004614ed4565b612611565b348015610958575f80fd5b506103c1610967366004614f01565b60a56020525f908152604090205481565b348015610983575f80fd5b506103c160a85481565b348015610998575f80fd5b506103ee6109a7366004615119565b6126c1565b3480156109b7575f80fd5b506103ee6109c6366004614f01565b6129ce565b3480156109d6575f80fd5b506103ee6109e5366004614fa7565b612a27565b3480156109f5575f80fd5b506103ee610a04366004615119565b612db8565b348015610a14575f80fd5b506103ee610a2336600461518d565b612e41565b348015610a33575f80fd5b506103ee610a42366004614ed4565b612f7f565b6103ee610a553660046151bf565b613022565b348015610a65575f80fd5b506103c160985481565b348015610a7a575f80fd5b506103ee610a89366004614ed4565b6135b4565b348015610a99575f80fd5b506103ee610aa8366004614f01565b613723565b348015610ab8575f80fd5b506103c160ac5481565b348015610acd575f80fd5b50610397610adc366004614ed4565b6137e2565b348015610aec575f80fd5b506103c1609a5481565b348015610b01575f80fd5b506103ee610b10366004614ed4565b61382c565b348015610b20575f80fd5b506103ee610b2f366004614f01565b6138cf565b348015610b3f575f80fd5b506103ee610b4e366004614f01565b61395c565b348015610b5e575f80fd5b506103c160a95481565b610b70613c0d565b6001600160a01b0381165f908152609f602052604090205460ff1615610bdd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c42613c0d565b5f8111610c915760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bd4565b5f80610c9d8585613c67565b915091505f610cb0836001015160c01c90565b5f81815260a160205260409020549091508214610d0f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f60a181610d1d8785615214565b81526020019081526020015f205414610d9d5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b609d548111610e145760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b610e1f600182615227565b609e555b8315610f6e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e6b816137e2565b15610ec6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610eb6908490615214565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f26575060a85481145b15610f30575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e23575b505050505050565b60a85415610fc65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b610fce613d0f565b5f80610fda8484613c67565b915091505f610fed836001015160c01c90565b5f81815260a16020526040902054909150821461104c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61105581611852565b6110a15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b6110aa816137e2565b156110f75760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a4602052604090206003015460ff16156111585760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bd4565b5f81815260a260205260409020600101544210156111b85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bd4565b605983015160a05f6111cb600185615227565b81526020019081526020015f2054146112265760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f81815260a06020526040902054156112815760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bd4565b80609d54600101146112d55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b609d819055600160a35f6112ea866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561133961132c846011015160c01c90565b600985015160c01c613d62565b60a25f611347600184615227565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113a39084615227565b81526020019081526020015f205f905560ad5f6001836113c39190615227565b81526020019081526020015f205f905560a45f6001836113e39190615227565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61146f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156114e35760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6114eb613d0f565b60ac54609e545f90815260a260205260408120549091429161150d9190615214565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611589919061523a565b6115939190615214565b109050811580156115a15750805b15611608575f6115b76080890160608a01615251565b61ffff16116116085760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b81806116115750805b61165d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bd4565b5f61167361166e60208a018a615272565b613c67565b5090505f611685826001015160c01c90565b611690906001615214565b5f81815260ad60205260408120549192509015611730575f491561171c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bd4565b505f81815260ad602052604090205461174b565b61174861174060208c018c6152d3565b60ff16613e19565b90505b6117568a5f83613f54565b5f806117628b8b613c67565b915091505f611775836001015160c01c90565b905080609e54146117c85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146118245760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f81815260a26020526040902042600190910155611843838b8b6144aa565b50505050505050505050505050565b5f81815260a260205260408120541580159061187a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191091906152f3565b61195c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a854156119ac5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6119b4613d0f565b5f6119c561166e6020840184615272565b5090505f6119d7826001015160c01c90565b6119e2906001615214565b5f81815260ad602052604090205490915015611a665760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aee919061523a565b611af89190615214565b1015611b60575f611b0f6080850160608601615251565b61ffff1611611b605760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b5f611b7161174060208601866152d3565b9050611b7e843383613f54565b50505050565b611b8c613c0d565b5f81118015611b9d57506099548114155b611be95760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bd4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c4f57505f5460ff8083169116105b611cc15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff831617610100179055611cdf5f5460ff1690565b60ff16600214611d315760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bd4565b81611da45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bd4565b609e545f90815260ab6020526040902054611dcd57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e9a91906152f3565b611ee65760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a85415611f365760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b611f3e613d0f565b5f4915611f8d5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bd4565b5f611f9e61166e6020840184615272565b5090505f611fb0826001015160c01c90565b611fbb906001615214565b5f81815260ad602052604090205490915061203e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120c6919061523a565b6120d09190615214565b1015612138575f6120e76080850160608601615251565b61ffff16116121385760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b61215083335f84815260ad6020526040902054613f54565b505050565b61215d613c0d565b6001600160a01b0381165f908152609f602052604090205460ff166121c45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bd4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c2f565b61221a613c0d565b6122235f61465d565b565b5f54610100900460ff161580801561224357505f54600160ff909116105b8061225c5750303b15801561225c57505f5460ff166001145b6122ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805460ff1916600117905580156122ef575f805461ff0019166101001790555b6001600160a01b038616158061230c57506001600160a01b038516155b15612343576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123995760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bd4565b6123a16146c6565b6123a961474a565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612525575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612536613c0d565b6001600160a01b0381161580159061255c5750609c546001600160a01b03828116911614155b6125a85760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bd4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612619613c0d565b5f81118015612629575060648111155b8015612637575060a9548114155b6126835760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bd4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c23565b60a854156127115760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b612719613d0f565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612785573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127a991906152f3565b6127f55760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b5f806128018686613c67565b915091505f612814836001015160c01c90565b5f81815260a1602052604090205490915082146128735760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61287c816137e2565b6128c85760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff19169055609954600290910154429161290491615214565b11612983575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f7574000000000000000000000000000000000000000000000000009183019190915261297e9183916001600160a01b0316906147ce565b612525565b61298e8386866144aa565b61252581336040518060400160405280600d81526020017f50726f6f6620737563636573730000000000000000000000000000000000000081525061492d565b6129d6613c0d565b60aa80545f9091556129e882826149f9565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c23565b612a2f613c0d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612aa65760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bd4565b5f80612ab28484613c67565b915091505f612ac5836001015160c01c90565b90508015612b155760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bd4565b5f612b21846079015190565b905080612b705760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bd4565b600984015160c01c15612bc55760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bd4565b5f612bd1856019015190565b03612c1e5760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bd4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c4a856039015190565b14612c975760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bd4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612dc48686613c67565b915091505f612dd7836001015160c01c90565b5f81815260a160205260409020549091508214612e365760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6125258386866144aa565b612e49613c0d565b8015612f4d57612e57614aa2565b60a65460ff1615612f0c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612eab908490615214565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f55614afc565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f2f565b50565b612f87613c0d565b5f81118015612f98575060ac548114155b612fe45760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bd4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c23565b335f908152609f602052604090205460ff166130805760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bd4565b60a854156130d05760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6130d8613d0f565b60a65460ff161561312b5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bd4565b8167ffffffffffffffff16609d54106131865760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a1602052604090205481146131ed5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6132008267ffffffffffffffff16611852565b61324c5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132c75760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133575760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bd4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133cb919061523a565b34101561341a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161353291815260200190565b60405180910390a35f609d54600161354a9190615214565b90505b609e5481116135a2578267ffffffffffffffff168114613590576099545f82815260a260205260408120600101805490919061358a908490615214565b90915550505b8061359a8161530e565b91505061354d565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135d457505f5460ff8083169116105b6136465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001781558290036136a85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bd4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b335f90815260a56020526040812054908190036137825760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bd4565b335f90815260a5602052604081205561379b82826149f9565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137d691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061187a5750505f90815260a46020526040902060030154610100900460ff161590565b613834613c0d565b5f8111801561384557506098548114155b6138915760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bd4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c23565b6138d7613c0d565b6001600160a01b0381166139535760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bd4565b612f7c8161465d565b5f54600490610100900460ff1615801561397c57505f5460ff8083169116105b6139ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001790556001600160a01b03821615801590613a2257505f826001600160a01b03163b115b613a6e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bd4565b609d54609e5414613ac15760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610bd4565b60a65460ff1615613b145760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bd4565b60a85415613b645760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6097546040516001600160a01b038085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6033546001600160a01b031633146122235760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bd4565b5f805f613c748585614b35565b90505f8160ff165f03613c9557613c8b8686614ba5565b9094509050613d01565b8160ff1660011480613caa57508160ff166002145b15613cb957613c8b8686614c0e565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bd4565b808420925050509250929050565b60655460ff16156122235760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bd4565b805f03613d6d575050565b8082035f5b82811015611b7e57610100818403811115613d8c57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613def575f80fd5b505af1158015613e01573d5f803e3d5ffd5b50505050610100830192505061010081019050613d72565b5f81600203613ea8575f6040515f5b804980613e355750613e44565b60208202830152600101613e28565b602081028083209201604052909250905080613ea25760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bd4565b50919050565b60014915613f1e5760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bd4565b5f4915613f2c575f4961187a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002613f6360208501856152d3565b60ff161115613fb45760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bd4565b60808301356140055760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bd4565b60a08301356140565760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bd4565b5f8061406861166e6020870187615272565b915091505f61407b836001015160c01c90565b90505f60a18161408c846001615214565b81526020019081526020015f2054146140e75760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bd4565b609e5481146141385760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146141945760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bd4565b5f81815260ab60205260409020546080870135146141f45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f614203846011015160c01c90565b90505f61422f61421960608a0160408b01615345565b61422960808b0160608c01615251565b84614c61565b90506142416080890160608a01615251565b60019384019361ffff91909116929092019160f99061426360208b018b6152d3565b60ff161061427057506101015b6040805182810190915295506142958661428d60208c018c6152d3565b60ff16614ca5565b60c084901b60018701526142c3866142b360808c0160608d01615251565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161431360208b018b6152d3565b60ff1610614345576143458661432f60608c0160408d01615345565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156143ae5760a7545f90815260a4602052604090206002015460995442916143a191615214565b6143ab9190615227565b90505b604051806080016040528042815260200182609854426143ce9190615214565b6143d89190615214565b81526020016143ed60608d0160408e01615345565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806144f75760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bd4565b5f614506846001015160c01c90565b90505f614514856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614543876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a848614605885160f81c90565b858888866040518663ffffffff1660e01b815260040161462995949392919061535e565b5f6040518083038186803b15801561463f575f80fd5b505afa158015614651573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147425760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614cac565b5f54610100900460ff166147c65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614d34565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614855573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614879919061523a565b5f86815260a46020526040902060010154909150614898908290615214565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906148d7908490615214565b90915550506040516148ea9084906153c1565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061495190846153ed565b61495b9190615404565b90506149678183615227565b60aa5f8282546149779190615214565b90915550506001600160a01b0384165f90815260a56020526040812080548392906149a3908490615214565b90915550506040516149b69084906153c1565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614a9e575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a48576040519150601f19603f3d011682016040523d82523d5f602084013e614a4d565b606091505b50509050806121505760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bd4565b5050565b614aaa613d0f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614adf3390565b6040516001600160a01b03909116815260200160405180910390a1565b614b04614db9565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614adf565b5f81614b835760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bd4565b82825f818110614b9557614b9561543c565b919091013560f81c949350505050565b5f8160f9811015614bf85760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bd4565b6040519150808483378082016040529250929050565b5f816101018114614bf85760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bd4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614c968161ffff871686614e0b565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614d285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6065805460ff19169055565b5f54610100900460ff16614db05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6122233361465d565b60655460ff166122235760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bd4565b5f825f03614e1a575082614ecd565b609b546001600160a01b03165f5b84811015614ec7576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614e8e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614eb2919061523a565b87525060209095019460019384019301614e28565b50849150505b9392505050565b5f60208284031215614ee4575f80fd5b5035919050565b80356001600160a01b0381168114613f4f575f80fd5b5f60208284031215614f11575f80fd5b614ecd82614eeb565b5f8083601f840112614f2a575f80fd5b50813567ffffffffffffffff811115614f41575f80fd5b602083019150836020828501011115614f58575f80fd5b9250929050565b5f805f60408486031215614f71575f80fd5b833567ffffffffffffffff811115614f87575f80fd5b614f9386828701614f1a565b909790965060209590950135949350505050565b5f8060208385031215614fb8575f80fd5b823567ffffffffffffffff811115614fce575f80fd5b614fda85828601614f1a565b90969095509350505050565b5f60e08284031215613ea2575f80fd5b5f805f805f6060868803121561500a575f80fd5b853567ffffffffffffffff80821115615021575f80fd5b61502d89838a01614fe6565b96506020880135915080821115615042575f80fd5b61504e89838a01614f1a565b90965094506040880135915080821115615066575f80fd5b5061507388828901614f1a565b969995985093965092949392505050565b5f60208284031215615094575f80fd5b813567ffffffffffffffff8111156150aa575f80fd5b6150b684828501614fe6565b949350505050565b5f805f805f8060c087890312156150d3575f80fd5b6150dc87614eeb565b95506150ea60208801614eeb565b94506150f860408801614eeb565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561512c575f80fd5b843567ffffffffffffffff80821115615143575f80fd5b61514f88838901614f1a565b90965094506020870135915080821115615167575f80fd5b5061517487828801614f1a565b95989497509550505050565b8015158114612f7c575f80fd5b5f6020828403121561519d575f80fd5b8135614ecd81615180565b803567ffffffffffffffff81168114613f4f575f80fd5b5f80604083850312156151d0575f80fd5b6151d9836151a8565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561187a5761187a6151e7565b8181038181111561187a5761187a6151e7565b5f6020828403121561524a575f80fd5b5051919050565b5f60208284031215615261575f80fd5b813561ffff81168114614ecd575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152a5575f80fd5b83018035915067ffffffffffffffff8211156152bf575f80fd5b602001915036819003821315614f58575f80fd5b5f602082840312156152e3575f80fd5b813560ff81168114614ecd575f80fd5b5f60208284031215615303575f80fd5b8151614ecd81615180565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361533e5761533e6151e7565b5060010190565b5f60208284031215615355575f80fd5b614ecd826151a8565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156153e057602081860181015185830152016153c6565b505f920191825250919050565b808202811582820484141761187a5761187a6151e7565b5f82615437577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bin/submitter_deployed.hex b/bindings/bin/submitter_deployed.hex new file mode 100644 index 000000000..6ca10a562 --- /dev/null +++ b/bindings/bin/submitter_deployed.hex @@ -0,0 +1 @@ +0x608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611bc0565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611be0565b6105d2565b3480156101ef575f80fd5b5061019b6101fe366004611be0565b610678565b61019b61071e565b348015610216575f80fd5b50610239610225366004611bc0565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b6108b3565b348015610268575f80fd5b506101b2610277366004611bc0565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b6109f0565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611bc0565b610a01565b348015610326575f80fd5b5061019b610335366004611bc0565b610a92565b348015610345575f80fd5b5061019b610354366004611be0565b610c83565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611bc0565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611bc0565b610d36565b3480156103f2575f80fd5b506101b2610401366004611bc0565b610ece565b348015610411575f80fd5b5061019b610420366004611bc0565b611085565b348015610430575f80fd5b5061019b61043f366004611bf7565b6111b1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611bc0565b6115f9565b610480611693565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b61057a5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105da611693565b5f811180156105eb57506098548114155b6106375760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610680611693565b5f8111801561069157506099548114155b6106dd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107266116fa565b335f818152609c602052604090205460ff168015610769575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107b55760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546107e5903490611c6d565b90505f341180156107f857506098548110155b6108445760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108b16001606555565b565b335f818152609c602052604090205460ff1680156108f6575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610925575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109715760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b6109f8611693565b6108b15f61175a565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a5a575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a8c575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a9a6116fa565b3373ffffffffffffffffffffffffffffffffffffffff8216610afe5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b725760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e6700000000000000000000000000000000006044820152606401610571565b610b7a6117d0565b610bc65760405162461bcd60e51b815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e656400000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e909252909120805460ff19169055610c0d83826118d8565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610c6c91815260200190565b60405180910390a35050610c806001606555565b50565b610c8b611693565b5f81118015610c9b575060648111155b8015610ca95750609a548114155b610cf55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610d3e611693565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610d97575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610de35760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610e8a5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e602052604090819020805460ff19166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e4490610e819084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f4d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610571565b610f556116fa565b73ffffffffffffffffffffffffffffffffffffffff8216610f7757505f611076565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216909155609a54606490610fd59083611c80565b610fdf9190611c97565b9150610feb8282611ccf565b609b5f828254610ffb9190611c6d565b90915550506097546110239073ffffffffffffffffffffffffffffffffffffffff16836118d8565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110806001606555565b919050565b61108d611693565b6110956116fa565b73ffffffffffffffffffffffffffffffffffffffff81166110f85760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b609b54806111485760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610571565b5f609b5561115682826118d8565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161119e91815260200190565b60405180910390a250610c806001606555565b5f54610100900460ff16158080156111cf57505f54600160ff909116105b806111e85750303b1580156111e857505f5460ff166001145b61125a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610571565b5f805460ff191660011790558015611298575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166112fb5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff85161580159061133657505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113825760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610571565b5f84116113d15760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b5f83116114205760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b5f82118015611430575060648211155b61147c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b611484611994565b61148c611a18565b6114958661175a565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156115f1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611601611693565b73ffffffffffffffffffffffffffffffffffffffff811661168a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610571565b610c808161175a565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108b15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610571565b60026065540361174c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610571565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611840573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118649190611ce2565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118d19190611ce2565b1491505090565b805f036118e3575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611939576040519150601f19603f3d011682016040523d82523d5f602084013e61193e565b606091505b505090508061198f5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610571565b505050565b5f54610100900460ff16611a105760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611a9c565b5f54610100900460ff16611a945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611b21565b5f54610100900460ff16611b185760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b13361175a565b5f54610100900460ff166117535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b803573ffffffffffffffffffffffffffffffffffffffff81168114611080575f80fd5b5f60208284031215611bd0575f80fd5b611bd982611b9d565b9392505050565b5f60208284031215611bf0575f80fd5b5035919050565b5f805f805f60a08688031215611c0b575f80fd5b611c1486611b9d565b9450611c2260208701611b9d565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8c57610a8c611c40565b8082028115828204841417610a8c57610a8c611c40565b5f82611cca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8c57610a8c611c40565b5f60208284031215611cf2575f80fd5b505191905056fea164736f6c6343000818000a diff --git a/bindings/bindings/centralization_cleanup_test.go b/bindings/bindings/centralization_cleanup_test.go new file mode 100644 index 000000000..4947b69bb --- /dev/null +++ b/bindings/bindings/centralization_cleanup_test.go @@ -0,0 +1,99 @@ +package bindings + +import ( + "encoding/hex" + "strings" + "testing" +) + +func TestCurrentRollupBindingShape(t *testing.T) { + current, err := RollupMetaData.GetAbi() + if err != nil || current == nil { + t.Fatalf("parse generated Rollup ABI: %v", err) + } + if strings.Contains(RollupMetaData.ABI, "BatchSignatureInput") { + t.Fatal("generated Rollup binding still contains BatchSignatureInput") + } + + expected := map[string]struct { + selector string + inputs int + }{ + "commitBatch": {selector: "41f756da", inputs: 1}, + "commitState": {selector: "67caa37a", inputs: 1}, + "commitBatchWithProof": {selector: "1544ba3a", inputs: 3}, + "initialize4": {selector: "f8fa010f", inputs: 1}, + } + for name, want := range expected { + method, ok := current.Methods[name] + if !ok { + t.Fatalf("generated Rollup ABI is missing %s", name) + } + if got := hex.EncodeToString(method.ID); got != want.selector { + t.Fatalf("%s selector = %s, want %s", name, got, want.selector) + } + if got := len(method.Inputs); got != want.inputs { + t.Fatalf("%s input count = %d, want %d", name, got, want.inputs) + } + } + + batchDataStore, ok := current.Methods["batchDataStore"] + if !ok { + t.Fatal("generated Rollup ABI is missing batchDataStore") + } + if len(batchDataStore.Outputs) != 4 || batchDataStore.Outputs[3].Type.String() != "address" { + t.Fatalf("batchDataStore fourth output must be address: %v", batchDataStore.Outputs) + } + if _, ok := current.Methods["pendingBatchCount"]; ok { + t.Fatal("generated Rollup binding must not contain pendingBatchCount") + } +} + +func TestCurrentSubmitterBindingShape(t *testing.T) { + current, err := SubmitterMetaData.GetAbi() + if err != nil || current == nil { + t.Fatalf("parse generated Submitter ABI: %v", err) + } + for _, name := range []string{ + "addSubmitter", + "challengeDeposit", + "claimSlashRemaining", + "claimWithdrawal", + "initialize", + "isActive", + "removeSubmitter", + "slash", + "stake", + "withdraw", + } { + if _, ok := current.Methods[name]; !ok { + t.Fatalf("generated Submitter ABI is missing %s", name) + } + } +} + +func TestCurrentStorageLayoutsAreGenerated(t *testing.T) { + wantRollupSlots := map[string]uint{ + "submitterContract": 151, + "batchDataStore": 162, + "batchBlobVersionedHashes": 173, + } + for _, entry := range RollupStorageLayout.Storage { + if entry.Label == "pendingBatchCount" { + t.Fatal("Rollup storage layout must not contain pendingBatchCount") + } + if want, ok := wantRollupSlots[entry.Label]; ok { + if entry.Slot != want { + t.Fatalf("Rollup %s slot = %d, want %d", entry.Label, entry.Slot, want) + } + delete(wantRollupSlots, entry.Label) + } + } + if len(wantRollupSlots) != 0 { + t.Fatalf("Rollup storage layout is missing entries: %v", wantRollupSlots) + } + + if len(SubmitterStorageLayout.Storage) == 0 { + t.Fatal("Submitter storage layout was not generated") + } +} diff --git a/bindings/bindings/l1staking.go b/bindings/bindings/l1staking.go deleted file mode 100644 index 6ef653abe..000000000 --- a/bindings/bindings/l1staking.go +++ /dev/null @@ -1,3445 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/accounts/abi" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// L1StakingMetaData contains all meta data concerning the L1Staking contract. -var L1StakingMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"_messenger\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChallengeDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChallengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"Claimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitAddStakerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGasLimit\",\"type\":\"uint256\"}],\"name\":\"GasLimitRemoveStakersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"Registered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercentage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercentage\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"stakers\",\"type\":\"address[]\"}],\"name\":\"StakersRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldStakingValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStakingValue\",\"type\":\"uint256\"}],\"name\":\"StakingValueUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"WhitelistUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unlockHeight\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MESSENGER\",\"outputs\":[{\"internalType\":\"contractICrossDomainMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OTHER_STAKING\",\"outputs\":[{\"internalType\":\"contractStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"blsPubkey\",\"type\":\"bytes\"}],\"name\":\"blsKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cleanStakerStore\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"deleteList\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"deleteableHeight\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"height\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitAddStaker\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gasLimitRemoveStakers\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getActiveStakers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_staker\",\"type\":\"address\"}],\"name\":\"getStakerBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakers\",\"outputs\":[{\"internalType\":\"address[255]\",\"name\":\"\",\"type\":\"address[255]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"getStakersBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"bitmap\",\"type\":\"uint256\"}],\"name\":\"getStakersFromBitmap\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"stakerAddrs\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_rollupContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_lockBlocks\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isActiveStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isStakerInDeleteList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"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\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_stakers\",\"type\":\"address[]\"}],\"name\":\"removeStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"removedList\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"removed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sequencersBitmap\",\"type\":\"uint256\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakerIndexes\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"stakerSet\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"stakers\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"tmKey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blsKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakingValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"tmPubkey\",\"type\":\"bytes32\"}],\"name\":\"tmKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitAdd\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitAddStaker\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_gasLimitRemove\",\"type\":\"uint256\"}],\"name\":\"updateGasLimitRemoveStakers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rewardPercentage\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_stakingValue\",\"type\":\"uint256\"}],\"name\":\"updateStakingValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"add\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"remove\",\"type\":\"address[]\"}],\"name\":\"updateWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"verifySignature\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"stakerAddr\",\"type\":\"address\"}],\"name\":\"whitelist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"inWhitelist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawalLockBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"withdrawals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60c060405234801562000010575f80fd5b5060405162003e1d38038062003e1d833981016040819052620000339162000127565b6001600160a01b03811660805273530000000000000000000000000000000000001560a0526200006262000069565b5062000156565b5f54610100900460ff1615620000d55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161462000125575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000138575f80fd5b81516001600160a01b03811681146200014f575f80fd5b9392505050565b60805160a051613c826200019b5f395f8181610664015281816129530152612bc701525f818161043c01528181610701015281816129240152612b980152613c825ff3fe6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f1461090c578063f2fde38b1461092b578063f4fe7fef1461094a575f80fd5b8063d51c90a91461087f578063dd4785f514610894578063df155033146108d5575f80fd5b8063c7cd469a116100b7578063c7cd469a14610822578063cde4cd1114610841578063d096c3c614610860575f80fd5b8063ab8c53dc146107cf578063ae81de53146107e4578063bfa02ba914610803575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db91461077d578063a3066aab14610791578063a4f209b0146107b0575f80fd5b8063927ede2d146106f05780639b19251a146107235780639d48f41714610751575f80fd5b80638a565ac31161016c5780638a565ac3146106865780638da5cb5b146106a55780639168ae72146106c2575f80fd5b80637a9262a2146106085780638142951a14610634578063831cfb5814610653575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610588578063797adbde146105ae5780637a4e87c3146105cd575f80fd5b8063692c565b146105265780636f1e853314610555578063715018a614610574575f80fd5b80634d64903a1161022c5780634d64903a146104dd57806352d472eb146104f25780636801579114610507575f80fd5b806341de239b1461048857806343352d611461049d57806345bc4d10146104be575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461042e5780633ccfd60b146104605780633ee2a1f914610474575f80fd5b8063320ff860146103b257806335928991146103d15780633a9bbede146103f0575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613407565b610969565b005b34801561035a575f80fd5b50610312610369366004613461565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613481565b610d64565b6040516001600160a01b03909116815260200161031c565b3480156103bd575f80fd5b5061034d6103cc366004613498565b610d83565b3480156103dc575f80fd5b5061034d6103eb366004613481565b61109e565b3480156103fb575f80fd5b5061041e61040a366004613461565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610439575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b34801561046b575f80fd5b5061034d61114b565b34801561047f575f80fd5b5061034d611317565b348015610493575f80fd5b5061031260995481565b3480156104a8575f80fd5b506104b1611329565b60405161031c9190613540565b3480156104c9575f80fd5b506103126104d8366004613481565b61136f565b3480156104e8575f80fd5b5061031260985481565b3480156104fd575f80fd5b50610312609a5481565b348015610512575f80fd5b5061041e610521366004613461565b611675565b348015610531575f80fd5b5061041e610540366004613481565b6101a46020525f908152604090205460ff1681565b348015610560575f80fd5b5061041e61056f366004613461565b611710565b34801561057f575f80fd5b5061034d611789565b348015610593575f80fd5b5061041e6105a23660046135c2565b60019695505050505050565b3480156105b9575f80fd5b5061039a6105c8366004613481565b61179a565b3480156105d8575f80fd5b5061041e6105e7366004613668565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610613575f80fd5b50610312610622366004613461565b6101a56020525f908152604090205481565b34801561063f575f80fd5b5061034d61064e3660046136a2565b6117c3565b34801561065e575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610691575f80fd5b5061034d6106a0366004613481565b611c85565b3480156106b0575f80fd5b506033546001600160a01b031661039a565b3480156106cd575f80fd5b506106e16106dc366004613461565b611d28565b60405161031c9392919061373d565b3480156106fb575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072e575f80fd5b5061041e61073d366004613461565b609e6020525f908152604090205460ff1681565b34801561075c575f80fd5b5061077061076b366004613481565b611ddb565b60405161031c919061376d565b348015610788575f80fd5b50610770611ef8565b34801561079c575f80fd5b5061034d6107ab366004613461565b6120a6565b3480156107bb575f80fd5b5061034d6107ca366004613481565b6121d6565b3480156107da575f80fd5b50610312609d5481565b3480156107ef575f80fd5b5061034d6107fe366004613481565b612286565b34801561080e575f80fd5b5060975461039a906001600160a01b031681565b34801561082d575f80fd5b5061034d61083c3660046137b9565b612329565b34801561084c575f80fd5b5061034d61085b366004613461565b6124ca565b34801561086b575f80fd5b5061031261087a366004613461565b612538565b34801561088a575f80fd5b50610312609b5481565b34801561089f575f80fd5b506108c36108ae366004613461565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b3480156108e0575f80fd5b5061041e6108ef366004613461565b6001600160a01b03165f9081526101a16020526040902054151590565b348015610917575f80fd5b50610312610926366004613820565b6125b2565b348015610936575f80fd5b5061034d610945366004613461565b6126e4565b348015610955575f80fd5b5061034d610964366004613481565b612771565b335f818152609e602052604090205460ff166109cc5760405162461bcd60e51b815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a260205260409020546001600160a01b031615610a325760405162461bcd60e51b815260206004820152601260248201527f616c72656164792072656769737465726564000000000000000000000000000060448201526064016109c3565b8215801590610a5057505f8381526101a4602052604090205460ff16155b610a9c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b65790000000000000060448201526064016109c3565b8151610100148015610acf57506101a382604051610aba919061385f565b9081526040519081900360200190205460ff16155b610b1b5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420626c73207075626b6579000000000000000000000000000060448201526064016109c3565b6098543414610b6c5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b6040518060600160405280610b7e3390565b6001600160a01b03908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610bf1908261390f565b50905050610c04610bff3390565b612814565b60016101a383604051610c17919061385f565b90815260408051918290036020908101909220805493151560ff199485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610c763390565b8484604051610c879392919061373d565b60405180910390a1335f9081526101a26020908152604091829020825160608101845281546001600160a01b03168152600182015492810192909252600281018054610d5f9484019190610cda9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054610d069061387a565b8015610d515780601f10610d2857610100808354040283529160200191610d51565b820191905f5260205f20905b815481529060010190602001808311610d3457829003601f168201915b505050505081525050612922565b505050565b60a08160ff8110610d73575f80fd5b01546001600160a01b0316905081565b610d8b612a4a565b5f5b815181101561105a57610db8828281518110610dab57610dab613a0d565b6020026020010151611675565b610e2a5760405162461bcd60e51b815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016109c3565b6101a55f838381518110610e4057610e40613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20545f14610eb65760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b609954610ec39043613a67565b6101a55f848481518110610ed957610ed9613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2081905550610f26828281518110610f1957610f19613a0d565b6020026020010151612aa4565b818181518110610f3857610f38613a0d565b60200260200101516001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f858581518110610f8057610f80613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054604051610fb791815260200190565b60405180910390a2609e5f838381518110610fd457610fd4613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f84848151811061102157611021613a0d565b6020908102919091018101516001600160a01b031682528101919091526040015f20805460ff1916911515919091179055600101610d8d565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b60405180910390a161109b81612b96565b50565b6110a6612a4a565b5f811180156110b857506101a6548114155b6111045760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61115433611675565b6111a05760405162461bcd60e51b815260206004820152601260248201527f6f6e6c7920616374697665207374616b6572000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040902054156111fd5760405162461bcd60e51b815260206004820152600b60248201527f7769746864726177696e6700000000000000000000000000000000000000000060448201526064016109c3565b60995461120a9043613a67565b335f8181526101a5602052604090209190915561122690612aa4565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e60209081526040808320805460ff19908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f815181106112c8576112c8613a0d565b60200260200101906001600160a01b031690816001600160a01b0316815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161108a919061376d565b61131f612a4a565b611327612c8e565b565b6113316132d4565b60408051611fe08101918290529060a09060ff9082845b81546001600160a01b03168152600190910190602001808311611348575050505050905090565b6097545f906001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016109c3565b6113dc612f59565b5f6113e683611ddb565b90505f805b8251811015611598575f6101a55f85848151811061140b5761140b613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054111561148e576101a55f84838151811061144f5761144f613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f9055609854826114879190613a67565b9150611590565b6114c88382815181106114a3576114a3613a0d565b60200260200101516001600160a01b03165f9081526101a16020526040902054151590565b611590576098546114d99083613a67565b91506114f0838281518110610f1957610f19613a0d565b609e5f84838151811061150557611505613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81549060ff02191690556001609f5f85848151811061155257611552613a0d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b6001016113eb565b505f6064609a54836115aa9190613a7a565b6115b49190613a91565b90506115c08183613ac9565b609d5f8282546115d09190613a67565b90915550506097546115eb906001600160a01b031682612fb2565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161161a919061376d565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c8483604051611651919061376d565b60405180910390a161166283612b96565b925050506116706001606555565b919050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361169e57505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906116c99060019060ff16613adc565b60ff1660ff81106116dc576116dc613a0d565b01546001600160a01b031614801561170a57506001600160a01b0382165f9081526101a16020526040902054155b92915050565b6001600160a01b0381165f90815261019f602052604081205460ff16810361173957505f919050565b6001600160a01b0382165f81815261019f602052604090205460a0906117649060019060ff16613adc565b60ff1660ff811061177757611777613a0d565b01546001600160a01b03161492915050565b611791612a4a565b6113275f613062565b6101a081815481106117aa575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f54610100900460ff16158080156117e157505f54600160ff909116105b806117fa5750303b1580156117fa57505f5460ff166001145b61186c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016109c3565b5f805460ff1916600117905580156118aa575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0388166119005760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016109c3565b5f871161194f5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b5f861161199e5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c75650060448201526064016109c3565b5f85116119ed5760405162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b73000060448201526064016109c3565b5f8311611a3c5760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b65720000000060448201526064016109c3565b5f8211611a8b5760405162461bcd60e51b815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b65727360448201526064016109c3565b5f84118015611a9b575060648411155b611b0c5760405162461bcd60e51b8152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f746167650000000000000000000000000000000000000000000000000000000060648201526084016109c3565b611b146130cb565b611b1c61314f565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015611c7b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b611c8d612a4a565b5f81118015611c9e5750609c548114155b611cea5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910161113f565b6101a26020525f90815260409020805460018201546002830180546001600160a01b03909316939192611d5a9061387a565b80601f0160208091040260200160405190810160405280929190818152602001828054611d869061387a565b8015611dd15780601f10611da857610100808354040283529160200191611dd1565b820191905f5260205f20905b815481529060010190602001808311611db457829003601f168201915b5050505050905083565b6060600182901c5f5b8115611e0b57611df5816001613a67565b9050611e02600183613ac9565b82169150611de4565b8067ffffffffffffffff811115611e2457611e2461333d565b604051908082528060200260200182016040528015611e4d578160200160208202803683370190505b5092505f60015b60ff8160ff1611611eef57600160ff82161b861615611edd5760a0611e7a600183613adc565b60ff1660ff8110611e8d57611e8d613a0d565b015485516001600160a01b0390911690869084908110611eaf57611eaf613a0d565b6001600160a01b0390921660209283029190910190910152611ed2826001613a67565b915082821015611eef575b80611ee781613af5565b915050611e54565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff811015611fc7575f60a08260ff8110611f4057611f40613a0d565b01546001600160a01b031614801590611f8857506101a15f60a08360ff8110611f6b57611f6b613a0d565b01546001600160a01b0316815260208101919091526040015f2054155b15611fbf5782611f9781613b13565b9350506001828281518110611fae57611fae613a0d565b911515602092830291909101909101525b600101611f23565b505f8267ffffffffffffffff811115611fe257611fe261333d565b60405190808252806020026020018201604052801561200b578160200160208202803683370190505b5090505f805b60ff81101561209c5783818151811061202c5761202c613a0d565b6020026020010151156120945760a08160ff811061204c5761204c613a0d565b015483516001600160a01b039091169084908490811061206e5761206e613a0d565b6001600160a01b03909216602092830291909101909101528161209081613b13565b9250505b600101612011565b5090949350505050565b6120ae612f59565b335f9081526101a5602052604090205461210a5760405162461bcd60e51b815260206004820152601460248201527f7769746864726177616c206e6f7420657869737400000000000000000000000060448201526064016109c3565b335f9081526101a560205260409020544310156121695760405162461bcd60e51b815260206004820152601160248201527f7769746864726177616c206c6f636b656400000000000000000000000000000060448201526064016109c3565b335f9081526101a56020526040812055612181612c8e565b604080516001600160a01b0383168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a26121cc81609854612fb2565b61109b6001606555565b6121de612a4a565b5f811180156121ee575060648111155b80156121fc5750609a548114155b6122485760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016109c3565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910161113f565b61228e612a4a565b5f8111801561229f5750609b548114155b6122eb5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206e657720676173206c696d6974000000000000000000000060448201526064016109c3565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910161113f565b612331612a4a565b5f5b8381101561242957609f5f86868481811061235057612350613a0d565b90506020020160208101906123659190613461565b6001600160a01b0316815260208101919091526040015f205460ff16156123ce5760405162461bcd60e51b815260206004820152600f60248201527f696e2072656d6f766564206c697374000000000000000000000000000000000060448201526064016109c3565b6001609e5f8787858181106123e5576123e5613a0d565b90506020020160208101906123fa9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916911515919091179055600101612333565b505f5b8181101561248657609e5f84848481811061244957612449613a0d565b905060200201602081019061245e9190613461565b6001600160a01b0316815260208101919091526040015f20805460ff1916905560010161242c565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622848484846040516124bc9493929190613b8f565b60405180910390a150505050565b6124d2612a4a565b6124da612f59565b609d546124e78282612fb2565b5f609d55604080516001600160a01b0384168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a15061109b6001606555565b5f61254282611710565b61258e5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b506001600160a01b03165f90815261019f6020526040902054600160ff9091161b90565b5f60ff8211156126045760405162461bcd60e51b815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e64730000000060448201526064016109c3565b5f5b828110156126dd5761263884848381811061262357612623613a0d565b905060200201602081019061056f9190613461565b6126845760405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207374616b657200000000000000000000000000000000000060448201526064016109c3565b61019f5f85858481811061269a5761269a613a0d565b90506020020160208101906126af9190613461565b6001600160a01b0316815260208101919091526040015f2054600160ff90911681901b929092179101612606565b5092915050565b6126ec612a4a565b6001600160a01b0381166127685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016109c3565b61109b81613062565b612779612a4a565b5f8111801561278a57506098548114155b6127d65760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964207374616b696e672076616c7565000000000000000000000060448201526064016109c3565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368910161113f565b5f5b60ff8160ff1610156128d9575f60a060ff80841690811061283957612839613a0d565b01546001600160a01b0316036128d1578160a08260ff1660ff811061286057612860613a0d565b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03929092169190911790556128a2816001613bc0565b6001600160a01b03929092165f90815261019f60205260409020805460ff191660ff9093169290921790915550565b600101612816565b5060405162461bcd60e51b815260206004820152600960248201527f736c6f742066756c6c000000000000000000000000000000000000000000000060448201526064016109c3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016129849190613bd9565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f604051808303815f87803b158015612a31575f80fd5b505af1158015612a43573d5f803e3d5ffd5b5050505050565b6033546001600160a01b031633146113275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109c3565b6001600160a01b0381165f9081526101a1602052604090205415612b0a5760405162461bcd60e51b815260206004820152601560248201527f616c726561647920696e2064656c6574654c697374000000000000000000000060448201526064016109c3565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316179055609954612b7a9043613a67565b6001600160a01b039091165f9081526101a16020526040902055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f84604051602401612bf8919061376d565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152612a1a9493929190600401613c10565b5f5b6101a05481101561109b57436101a15f6101a08481548110612cb457612cb4613a0d565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205411612f475760a0600161019f5f6101a08581548110612cf957612cf9613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054612d2a919060ff16613adc565b60ff1660ff8110612d3d57612d3d613a0d565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110612d7f57612d7f613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120805460ff191690556101a080546101a292919084908110612dc557612dc5613a0d565b5f9182526020808320909101546001600160a01b03168352820192909252604001812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810182905590612e2360028301826132f3565b50506101a15f6101a08381548110612e3d57612e3d613a0d565b5f9182526020808320909101546001600160a01b031683528201929092526040018120556101a08054612e7290600190613ac9565b81548110612e8257612e82613a0d565b5f918252602090912001546101a080546001600160a01b039092169183908110612eae57612eae613a0d565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506101a0805480612eeb57612eeb613c48565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055612c90565b80612f5181613b13565b915050612c90565b600260655403612fab5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109c3565b6002606555565b8015613057575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613001576040519150601f19603f3d011682016040523d82523d5f602084013e613006565b606091505b5050905080610d5f5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c6564000000000060448201526064016109c3565b5050565b6001606555565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166131475760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b6113276131d3565b5f54610100900460ff166131cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b611327613258565b5f54610100900460ff1661324f5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b61132733613062565b5f54610100900460ff1661305b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016109c3565b60405180611fe0016040528060ff906020820280368337509192915050565b5080546132ff9061387a565b5f825580601f1061330e575050565b601f0160209004905f5260205f209081019061109b91905b80821115613339575f8155600101613326565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133935761339361333d565b604052919050565b5f82601f8301126133aa575f80fd5b813567ffffffffffffffff8111156133c4576133c461333d565b6133d76020601f19601f8401160161336a565b8181528460208386010111156133eb575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613418575f80fd5b82359150602083013567ffffffffffffffff811115613435575f80fd5b6134418582860161339b565b9150509250929050565b80356001600160a01b0381168114611670575f80fd5b5f60208284031215613471575f80fd5b61347a8261344b565b9392505050565b5f60208284031215613491575f80fd5b5035919050565b5f60208083850312156134a9575f80fd5b823567ffffffffffffffff808211156134c0575f80fd5b818501915085601f8301126134d3575f80fd5b8135818111156134e5576134e561333d565b8060051b91506134f684830161336a565b818152918301840191848101908884111561350f575f80fd5b938501935b83851015613534576135258561344b565b82529385019390850190613514565b98975050505050505050565b611fe0810181835f5b60ff8110156135715781516001600160a01b0316835260209283019290910190600101613549565b50505092915050565b5f8083601f84011261358a575f80fd5b50813567ffffffffffffffff8111156135a1575f80fd5b6020830191508360208260051b85010111156135bb575f80fd5b9250929050565b5f805f805f80608087890312156135d7575f80fd5b86359550602087013567ffffffffffffffff808211156135f5575f80fd5b6136018a838b0161357a565b9097509550604089013594506060890135915080821115613620575f80fd5b818901915089601f830112613633575f80fd5b813581811115613641575f80fd5b8a6020828501011115613652575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613678575f80fd5b813567ffffffffffffffff81111561368e575f80fd5b61369a8482850161339b565b949350505050565b5f805f805f805f60e0888a0312156136b8575f80fd5b6136c18861344b565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561370a5781810151838201526020016136f2565b50505f910152565b5f81518084526137298160208601602086016136f0565b601f01601f19169290920160200192915050565b6001600160a01b0384168152826020820152606060408201525f6137646060830184613712565b95945050505050565b602080825282518282018190525f9190848201906040850190845b818110156137ad5783516001600160a01b031683529284019291840191600101613788565b50909695505050505050565b5f805f80604085870312156137cc575f80fd5b843567ffffffffffffffff808211156137e3575f80fd5b6137ef8883890161357a565b90965094506020870135915080821115613807575f80fd5b506138148782880161357a565b95989497509550505050565b5f8060208385031215613831575f80fd5b823567ffffffffffffffff811115613847575f80fd5b6138538582860161357a565b90969095509350505050565b5f82516138708184602087016136f0565b9190910192915050565b600181811c9082168061388e57607f821691505b6020821081036138c5577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610d5f57805f5260205f20601f840160051c810160208510156138f05750805b601f840160051c820191505b81811015612a43575f81556001016138fc565b815167ffffffffffffffff8111156139295761392961333d565b61393d81613937845461387a565b846138cb565b602080601f83116001811461398f575f84156139595750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a05565b5f85815260208120601f198616915b828110156139bd5788860151825594840194600190910190840161399e565b50858210156139f957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561170a5761170a613a3a565b808202811582820484141761170a5761170a613a3a565b5f82613ac4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8181038181111561170a5761170a613a3a565b60ff828116828216039081111561170a5761170a613a3a565b5f60ff821660ff8103613b0a57613b0a613a3a565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613b4357613b43613a3a565b5060010190565b8183525f60208085019450825f5b85811015613b84576001600160a01b03613b718361344b565b1687529582019590820190600101613b58565b509495945050505050565b604081525f613ba2604083018688613b4a565b8281036020840152613bb5818587613b4a565b979650505050505050565b60ff818116838216019081111561170a5761170a613a3a565b602081526001600160a01b038251166020820152602082015160408201525f604083015160608084015261369a6080840182613712565b6001600160a01b0385168152836020820152608060408201525f613c376080830185613712565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a", -} - -// L1StakingABI is the input ABI used to generate the binding from. -// Deprecated: Use L1StakingMetaData.ABI instead. -var L1StakingABI = L1StakingMetaData.ABI - -// L1StakingBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use L1StakingMetaData.Bin instead. -var L1StakingBin = L1StakingMetaData.Bin - -// DeployL1Staking deploys a new Ethereum contract, binding an instance of L1Staking to it. -func DeployL1Staking(auth *bind.TransactOpts, backend bind.ContractBackend, _messenger common.Address) (common.Address, *types.Transaction, *L1Staking, error) { - parsed, err := L1StakingMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(L1StakingBin), backend, _messenger) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil -} - -// L1Staking is an auto generated Go binding around an Ethereum contract. -type L1Staking struct { - L1StakingCaller // Read-only binding to the contract - L1StakingTransactor // Write-only binding to the contract - L1StakingFilterer // Log filterer for contract events -} - -// L1StakingCaller is an auto generated read-only Go binding around an Ethereum contract. -type L1StakingCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingTransactor is an auto generated write-only Go binding around an Ethereum contract. -type L1StakingTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type L1StakingFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// L1StakingSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type L1StakingSession struct { - Contract *L1Staking // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// L1StakingCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type L1StakingCallerSession struct { - Contract *L1StakingCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// L1StakingTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type L1StakingTransactorSession struct { - Contract *L1StakingTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// L1StakingRaw is an auto generated low-level Go binding around an Ethereum contract. -type L1StakingRaw struct { - Contract *L1Staking // Generic contract binding to access the raw methods on -} - -// L1StakingCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type L1StakingCallerRaw struct { - Contract *L1StakingCaller // Generic read-only contract binding to access the raw methods on -} - -// L1StakingTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type L1StakingTransactorRaw struct { - Contract *L1StakingTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewL1Staking creates a new instance of L1Staking, bound to a specific deployed contract. -func NewL1Staking(address common.Address, backend bind.ContractBackend) (*L1Staking, error) { - contract, err := bindL1Staking(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &L1Staking{L1StakingCaller: L1StakingCaller{contract: contract}, L1StakingTransactor: L1StakingTransactor{contract: contract}, L1StakingFilterer: L1StakingFilterer{contract: contract}}, nil -} - -// NewL1StakingCaller creates a new read-only instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingCaller(address common.Address, caller bind.ContractCaller) (*L1StakingCaller, error) { - contract, err := bindL1Staking(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &L1StakingCaller{contract: contract}, nil -} - -// NewL1StakingTransactor creates a new write-only instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingTransactor(address common.Address, transactor bind.ContractTransactor) (*L1StakingTransactor, error) { - contract, err := bindL1Staking(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &L1StakingTransactor{contract: contract}, nil -} - -// NewL1StakingFilterer creates a new log filterer instance of L1Staking, bound to a specific deployed contract. -func NewL1StakingFilterer(address common.Address, filterer bind.ContractFilterer) (*L1StakingFilterer, error) { - contract, err := bindL1Staking(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &L1StakingFilterer{contract: contract}, nil -} - -// bindL1Staking binds a generic wrapper to an already deployed contract. -func bindL1Staking(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := L1StakingMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_L1Staking *L1StakingRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _L1Staking.Contract.L1StakingCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_L1Staking *L1StakingRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.Contract.L1StakingTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_L1Staking *L1StakingRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _L1Staking.Contract.L1StakingTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_L1Staking *L1StakingCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _L1Staking.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_L1Staking *L1StakingTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_L1Staking *L1StakingTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _L1Staking.Contract.contract.Transact(opts, method, params...) -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingCaller) MESSENGER(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "MESSENGER") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingSession) MESSENGER() (common.Address, error) { - return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) -} - -// MESSENGER is a free data retrieval call binding the contract method 0x927ede2d. -// -// Solidity: function MESSENGER() view returns(address) -func (_L1Staking *L1StakingCallerSession) MESSENGER() (common.Address, error) { - return _L1Staking.Contract.MESSENGER(&_L1Staking.CallOpts) -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingCaller) OTHERSTAKING(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "OTHER_STAKING") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingSession) OTHERSTAKING() (common.Address, error) { - return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) -} - -// OTHERSTAKING is a free data retrieval call binding the contract method 0x831cfb58. -// -// Solidity: function OTHER_STAKING() view returns(address) -func (_L1Staking *L1StakingCallerSession) OTHERSTAKING() (common.Address, error) { - return _L1Staking.Contract.OTHERSTAKING(&_L1Staking.CallOpts) -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCaller) BlsKeys(opts *bind.CallOpts, blsPubkey []byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "blsKeys", blsPubkey) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingSession) BlsKeys(blsPubkey []byte) (bool, error) { - return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) -} - -// BlsKeys is a free data retrieval call binding the contract method 0x7a4e87c3. -// -// Solidity: function blsKeys(bytes blsPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCallerSession) BlsKeys(blsPubkey []byte) (bool, error) { - return _L1Staking.Contract.BlsKeys(&_L1Staking.CallOpts, blsPubkey) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "challengeDeposit") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingSession) ChallengeDeposit() (*big.Int, error) { - return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) -} - -// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. -// -// Solidity: function challengeDeposit() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) ChallengeDeposit() (*big.Int, error) { - return _L1Staking.Contract.ChallengeDeposit(&_L1Staking.CallOpts) -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingCaller) DeleteList(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "deleteList", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingSession) DeleteList(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) -} - -// DeleteList is a free data retrieval call binding the contract method 0x797adbde. -// -// Solidity: function deleteList(uint256 ) view returns(address) -func (_L1Staking *L1StakingCallerSession) DeleteList(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.DeleteList(&_L1Staking.CallOpts, arg0) -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingCaller) DeleteableHeight(opts *bind.CallOpts, stakerAddr common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "deleteableHeight", stakerAddr) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { - return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) -} - -// DeleteableHeight is a free data retrieval call binding the contract method 0x2e407a6f. -// -// Solidity: function deleteableHeight(address stakerAddr) view returns(uint256 height) -func (_L1Staking *L1StakingCallerSession) DeleteableHeight(stakerAddr common.Address) (*big.Int, error) { - return _L1Staking.Contract.DeleteableHeight(&_L1Staking.CallOpts, stakerAddr) -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingCaller) GasLimitAddStaker(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "gasLimitAddStaker") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingSession) GasLimitAddStaker() (*big.Int, error) { - return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) -} - -// GasLimitAddStaker is a free data retrieval call binding the contract method 0xd51c90a9. -// -// Solidity: function gasLimitAddStaker() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) GasLimitAddStaker() (*big.Int, error) { - return _L1Staking.Contract.GasLimitAddStaker(&_L1Staking.CallOpts) -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingCaller) GasLimitRemoveStakers(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "gasLimitRemoveStakers") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingSession) GasLimitRemoveStakers() (*big.Int, error) { - return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) -} - -// GasLimitRemoveStakers is a free data retrieval call binding the contract method 0x2108db35. -// -// Solidity: function gasLimitRemoveStakers() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) GasLimitRemoveStakers() (*big.Int, error) { - return _L1Staking.Contract.GasLimitRemoveStakers(&_L1Staking.CallOpts) -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingCaller) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getActiveStakers") - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingSession) GetActiveStakers() ([]common.Address, error) { - return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) -} - -// GetActiveStakers is a free data retrieval call binding the contract method 0x9fb82db9. -// -// Solidity: function getActiveStakers() view returns(address[]) -func (_L1Staking *L1StakingCallerSession) GetActiveStakers() ([]common.Address, error) { - return _L1Staking.Contract.GetActiveStakers(&_L1Staking.CallOpts) -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCaller) GetStakerBitmap(opts *bind.CallOpts, _staker common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakerBitmap", _staker) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) -} - -// GetStakerBitmap is a free data retrieval call binding the contract method 0xd096c3c6. -// -// Solidity: function getStakerBitmap(address _staker) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCallerSession) GetStakerBitmap(_staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakerBitmap(&_L1Staking.CallOpts, _staker) -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingCaller) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakers") - - if err != nil { - return *new([255]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([255]common.Address)).(*[255]common.Address) - - return out0, err - -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingSession) GetStakers() ([255]common.Address, error) { - return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) -} - -// GetStakers is a free data retrieval call binding the contract method 0x43352d61. -// -// Solidity: function getStakers() view returns(address[255]) -func (_L1Staking *L1StakingCallerSession) GetStakers() ([255]common.Address, error) { - return _L1Staking.Contract.GetStakers(&_L1Staking.CallOpts) -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCaller) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakersBitmap", _stakers) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) -} - -// GetStakersBitmap is a free data retrieval call binding the contract method 0xe2a6ad5f. -// -// Solidity: function getStakersBitmap(address[] _stakers) view returns(uint256 bitmap) -func (_L1Staking *L1StakingCallerSession) GetStakersBitmap(_stakers []common.Address) (*big.Int, error) { - return _L1Staking.Contract.GetStakersBitmap(&_L1Staking.CallOpts, _stakers) -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingCaller) GetStakersFromBitmap(opts *bind.CallOpts, bitmap *big.Int) ([]common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "getStakersFromBitmap", bitmap) - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { - return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) -} - -// GetStakersFromBitmap is a free data retrieval call binding the contract method 0x9d48f417. -// -// Solidity: function getStakersFromBitmap(uint256 bitmap) view returns(address[] stakerAddrs) -func (_L1Staking *L1StakingCallerSession) GetStakersFromBitmap(bitmap *big.Int) ([]common.Address, error) { - return _L1Staking.Contract.GetStakersFromBitmap(&_L1Staking.CallOpts, bitmap) -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsActiveStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isActiveStaker", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsActiveStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) -} - -// IsActiveStaker is a free data retrieval call binding the contract method 0x68015791. -// -// Solidity: function isActiveStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsActiveStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsActiveStaker(&_L1Staking.CallOpts, addr) -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isStaker", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) -} - -// IsStaker is a free data retrieval call binding the contract method 0x6f1e8533. -// -// Solidity: function isStaker(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsStaker(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStaker(&_L1Staking.CallOpts, addr) -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingCaller) IsStakerInDeleteList(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "isStakerInDeleteList", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingSession) IsStakerInDeleteList(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) -} - -// IsStakerInDeleteList is a free data retrieval call binding the contract method 0xdf155033. -// -// Solidity: function isStakerInDeleteList(address addr) view returns(bool) -func (_L1Staking *L1StakingCallerSession) IsStakerInDeleteList(addr common.Address) (bool, error) { - return _L1Staking.Contract.IsStakerInDeleteList(&_L1Staking.CallOpts, addr) -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingCaller) Messenger(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "messenger") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingSession) Messenger() (common.Address, error) { - return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) -} - -// Messenger is a free data retrieval call binding the contract method 0x3cb747bf. -// -// Solidity: function messenger() view returns(address) -func (_L1Staking *L1StakingCallerSession) Messenger() (common.Address, error) { - return _L1Staking.Contract.Messenger(&_L1Staking.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingSession) Owner() (common.Address, error) { - return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_L1Staking *L1StakingCallerSession) Owner() (common.Address, error) { - return _L1Staking.Contract.Owner(&_L1Staking.CallOpts) -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingCaller) RemovedList(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "removedList", stakerAddr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingSession) RemovedList(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) -} - -// RemovedList is a free data retrieval call binding the contract method 0x3a9bbede. -// -// Solidity: function removedList(address stakerAddr) view returns(bool removed) -func (_L1Staking *L1StakingCallerSession) RemovedList(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.RemovedList(&_L1Staking.CallOpts, stakerAddr) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "rewardPercentage") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingSession) RewardPercentage() (*big.Int, error) { - return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) -} - -// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. -// -// Solidity: function rewardPercentage() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) RewardPercentage() (*big.Int, error) { - return _L1Staking.Contract.RewardPercentage(&_L1Staking.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "rollupContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingSession) RollupContract() (common.Address, error) { - return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) -} - -// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. -// -// Solidity: function rollupContract() view returns(address) -func (_L1Staking *L1StakingCallerSession) RollupContract() (common.Address, error) { - return _L1Staking.Contract.RollupContract(&_L1Staking.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "slashRemaining") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingSession) SlashRemaining() (*big.Int, error) { - return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) -} - -// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. -// -// Solidity: function slashRemaining() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) SlashRemaining() (*big.Int, error) { - return _L1Staking.Contract.SlashRemaining(&_L1Staking.CallOpts) -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingCaller) StakerIndexes(opts *bind.CallOpts, stakerAddr common.Address) (uint8, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakerIndexes", stakerAddr) - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { - return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) -} - -// StakerIndexes is a free data retrieval call binding the contract method 0xdd4785f5. -// -// Solidity: function stakerIndexes(address stakerAddr) view returns(uint8 index) -func (_L1Staking *L1StakingCallerSession) StakerIndexes(stakerAddr common.Address) (uint8, error) { - return _L1Staking.Contract.StakerIndexes(&_L1Staking.CallOpts, stakerAddr) -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingCaller) StakerSet(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakerSet", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingSession) StakerSet(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) -} - -// StakerSet is a free data retrieval call binding the contract method 0x303afb9e. -// -// Solidity: function stakerSet(uint256 ) view returns(address) -func (_L1Staking *L1StakingCallerSession) StakerSet(arg0 *big.Int) (common.Address, error) { - return _L1Staking.Contract.StakerSet(&_L1Staking.CallOpts, arg0) -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingCaller) Stakers(opts *bind.CallOpts, stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakers", stakerAddr) - - outstruct := new(struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte - }) - if err != nil { - return *outstruct, err - } - - outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.TmKey = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - outstruct.BlsKey = *abi.ConvertType(out[2], new([]byte)).(*[]byte) - - return *outstruct, err - -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingSession) Stakers(stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) -} - -// Stakers is a free data retrieval call binding the contract method 0x9168ae72. -// -// Solidity: function stakers(address stakerAddr) view returns(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingCallerSession) Stakers(stakerAddr common.Address) (struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte -}, error) { - return _L1Staking.Contract.Stakers(&_L1Staking.CallOpts, stakerAddr) -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingCaller) StakingValue(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "stakingValue") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingSession) StakingValue() (*big.Int, error) { - return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) -} - -// StakingValue is a free data retrieval call binding the contract method 0x4d64903a. -// -// Solidity: function stakingValue() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) StakingValue() (*big.Int, error) { - return _L1Staking.Contract.StakingValue(&_L1Staking.CallOpts) -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCaller) TmKeys(opts *bind.CallOpts, tmPubkey [32]byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "tmKeys", tmPubkey) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingSession) TmKeys(tmPubkey [32]byte) (bool, error) { - return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) -} - -// TmKeys is a free data retrieval call binding the contract method 0x692c565b. -// -// Solidity: function tmKeys(bytes32 tmPubkey) view returns(bool exist) -func (_L1Staking *L1StakingCallerSession) TmKeys(tmPubkey [32]byte) (bool, error) { - return _L1Staking.Contract.TmKeys(&_L1Staking.CallOpts, tmPubkey) -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingCaller) VerifySignature(opts *bind.CallOpts, arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "verifySignature", arg0, arg1, arg2, arg3) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) -} - -// VerifySignature is a free data retrieval call binding the contract method 0x74fe27b7. -// -// Solidity: function verifySignature(uint256 , address[] , bytes32 , bytes ) pure returns(bool) -func (_L1Staking *L1StakingCallerSession) VerifySignature(arg0 *big.Int, arg1 []common.Address, arg2 [32]byte, arg3 []byte) (bool, error) { - return _L1Staking.Contract.VerifySignature(&_L1Staking.CallOpts, arg0, arg1, arg2, arg3) -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingCaller) Whitelist(opts *bind.CallOpts, stakerAddr common.Address) (bool, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "whitelist", stakerAddr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingSession) Whitelist(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) -} - -// Whitelist is a free data retrieval call binding the contract method 0x9b19251a. -// -// Solidity: function whitelist(address stakerAddr) view returns(bool inWhitelist) -func (_L1Staking *L1StakingCallerSession) Whitelist(stakerAddr common.Address) (bool, error) { - return _L1Staking.Contract.Whitelist(&_L1Staking.CallOpts, stakerAddr) -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingCaller) WithdrawalLockBlocks(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "withdrawalLockBlocks") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingSession) WithdrawalLockBlocks() (*big.Int, error) { - return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) -} - -// WithdrawalLockBlocks is a free data retrieval call binding the contract method 0x41de239b. -// -// Solidity: function withdrawalLockBlocks() view returns(uint256) -func (_L1Staking *L1StakingCallerSession) WithdrawalLockBlocks() (*big.Int, error) { - return _L1Staking.Contract.WithdrawalLockBlocks(&_L1Staking.CallOpts) -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingCaller) Withdrawals(opts *bind.CallOpts, staker common.Address) (*big.Int, error) { - var out []interface{} - err := _L1Staking.contract.Call(opts, &out, "withdrawals", staker) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingSession) Withdrawals(staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) -} - -// Withdrawals is a free data retrieval call binding the contract method 0x7a9262a2. -// -// Solidity: function withdrawals(address staker) view returns(uint256 amount) -func (_L1Staking *L1StakingCallerSession) Withdrawals(staker common.Address) (*big.Int, error) { - return _L1Staking.Contract.Withdrawals(&_L1Staking.CallOpts, staker) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "claimSlashRemaining", receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) -} - -// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. -// -// Solidity: function claimSlashRemaining(address receiver) returns() -func (_L1Staking *L1StakingTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimSlashRemaining(&_L1Staking.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "claimWithdrawal", receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) -} - -// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. -// -// Solidity: function claimWithdrawal(address receiver) returns() -func (_L1Staking *L1StakingTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.ClaimWithdrawal(&_L1Staking.TransactOpts, receiver) -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingTransactor) CleanStakerStore(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "cleanStakerStore") -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingSession) CleanStakerStore() (*types.Transaction, error) { - return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) -} - -// CleanStakerStore is a paid mutator transaction binding the contract method 0x3ee2a1f9. -// -// Solidity: function cleanStakerStore() returns() -func (_L1Staking *L1StakingTransactorSession) CleanStakerStore() (*types.Transaction, error) { - return _L1Staking.Contract.CleanStakerStore(&_L1Staking.TransactOpts) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactor) Initialize(opts *bind.TransactOpts, _rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "initialize", _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8142951a. -// -// Solidity: function initialize(address _rollupContract, uint256 _stakingValue, uint256 _challengeDeposit, uint256 _lockBlocks, uint256 _rewardPercentage, uint256 _gasLimitAdd, uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactorSession) Initialize(_rollupContract common.Address, _stakingValue *big.Int, _challengeDeposit *big.Int, _lockBlocks *big.Int, _rewardPercentage *big.Int, _gasLimitAdd *big.Int, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Initialize(&_L1Staking.TransactOpts, _rollupContract, _stakingValue, _challengeDeposit, _lockBlocks, _rewardPercentage, _gasLimitAdd, _gasLimitRemove) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingTransactor) Register(opts *bind.TransactOpts, tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "register", tmKey, blsKey) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) -} - -// Register is a paid mutator transaction binding the contract method 0x2a28e5a3. -// -// Solidity: function register(bytes32 tmKey, bytes blsKey) payable returns() -func (_L1Staking *L1StakingTransactorSession) Register(tmKey [32]byte, blsKey []byte) (*types.Transaction, error) { - return _L1Staking.Contract.Register(&_L1Staking.TransactOpts, tmKey, blsKey) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingTransactor) RemoveStaker(opts *bind.TransactOpts, _stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "removeStaker", _stakers) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) -} - -// RemoveStaker is a paid mutator transaction binding the contract method 0x320ff860. -// -// Solidity: function removeStaker(address[] _stakers) returns() -func (_L1Staking *L1StakingTransactorSession) RemoveStaker(_stakers []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.RemoveStaker(&_L1Staking.TransactOpts, _stakers) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "renounceOwnership") -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingSession) RenounceOwnership() (*types.Transaction, error) { - return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_L1Staking *L1StakingTransactorSession) RenounceOwnership() (*types.Transaction, error) { - return _L1Staking.Contract.RenounceOwnership(&_L1Staking.TransactOpts) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingTransactor) Slash(opts *bind.TransactOpts, sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "slash", sequencersBitmap) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) -} - -// Slash is a paid mutator transaction binding the contract method 0x45bc4d10. -// -// Solidity: function slash(uint256 sequencersBitmap) returns(uint256) -func (_L1Staking *L1StakingTransactorSession) Slash(sequencersBitmap *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.Slash(&_L1Staking.TransactOpts, sequencersBitmap) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "transferOwnership", newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address newOwner) returns() -func (_L1Staking *L1StakingTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.TransferOwnership(&_L1Staking.TransactOpts, newOwner) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, _challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateChallengeDeposit", _challengeDeposit) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) -} - -// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. -// -// Solidity: function updateChallengeDeposit(uint256 _challengeDeposit) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateChallengeDeposit(_challengeDeposit *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateChallengeDeposit(&_L1Staking.TransactOpts, _challengeDeposit) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingTransactor) UpdateGasLimitAddStaker(opts *bind.TransactOpts, _gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateGasLimitAddStaker", _gasLimitAdd) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) -} - -// UpdateGasLimitAddStaker is a paid mutator transaction binding the contract method 0xae81de53. -// -// Solidity: function updateGasLimitAddStaker(uint256 _gasLimitAdd) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitAddStaker(_gasLimitAdd *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitAddStaker(&_L1Staking.TransactOpts, _gasLimitAdd) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactor) UpdateGasLimitRemoveStakers(opts *bind.TransactOpts, _gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateGasLimitRemoveStakers", _gasLimitRemove) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) -} - -// UpdateGasLimitRemoveStakers is a paid mutator transaction binding the contract method 0x8a565ac3. -// -// Solidity: function updateGasLimitRemoveStakers(uint256 _gasLimitRemove) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateGasLimitRemoveStakers(_gasLimitRemove *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateGasLimitRemoveStakers(&_L1Staking.TransactOpts, _gasLimitRemove) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, _rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateRewardPercentage", _rewardPercentage) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) -} - -// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. -// -// Solidity: function updateRewardPercentage(uint256 _rewardPercentage) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateRewardPercentage(_rewardPercentage *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateRewardPercentage(&_L1Staking.TransactOpts, _rewardPercentage) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingTransactor) UpdateStakingValue(opts *bind.TransactOpts, _stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateStakingValue", _stakingValue) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) -} - -// UpdateStakingValue is a paid mutator transaction binding the contract method 0xf4fe7fef. -// -// Solidity: function updateStakingValue(uint256 _stakingValue) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateStakingValue(_stakingValue *big.Int) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateStakingValue(&_L1Staking.TransactOpts, _stakingValue) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingTransactor) UpdateWhitelist(opts *bind.TransactOpts, add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "updateWhitelist", add, remove) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) -} - -// UpdateWhitelist is a paid mutator transaction binding the contract method 0xc7cd469a. -// -// Solidity: function updateWhitelist(address[] add, address[] remove) returns() -func (_L1Staking *L1StakingTransactorSession) UpdateWhitelist(add []common.Address, remove []common.Address) (*types.Transaction, error) { - return _L1Staking.Contract.UpdateWhitelist(&_L1Staking.TransactOpts, add, remove) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { - return _L1Staking.contract.Transact(opts, "withdraw") -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingSession) Withdraw() (*types.Transaction, error) { - return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) -} - -// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. -// -// Solidity: function withdraw() returns() -func (_L1Staking *L1StakingTransactorSession) Withdraw() (*types.Transaction, error) { - return _L1Staking.Contract.Withdraw(&_L1Staking.TransactOpts) -} - -// L1StakingChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the L1Staking contract. -type L1StakingChallengeDepositUpdatedIterator struct { - Event *L1StakingChallengeDepositUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingChallengeDepositUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingChallengeDepositUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingChallengeDepositUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingChallengeDepositUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the L1Staking contract. -type L1StakingChallengeDepositUpdated struct { - OldChallengeDeposit *big.Int - NewChallengeDeposit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*L1StakingChallengeDepositUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return &L1StakingChallengeDepositUpdatedIterator{contract: _L1Staking.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil -} - -// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingChallengeDepositUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "ChallengeDepositUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingChallengeDepositUpdated) - if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. -// -// Solidity: event ChallengeDepositUpdated(uint256 oldChallengeDeposit, uint256 newChallengeDeposit) -func (_L1Staking *L1StakingFilterer) ParseChallengeDepositUpdated(log types.Log) (*L1StakingChallengeDepositUpdated, error) { - event := new(L1StakingChallengeDepositUpdated) - if err := _L1Staking.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingClaimedIterator is returned from FilterClaimed and is used to iterate over the raw logs and unpacked data for Claimed events raised by the L1Staking contract. -type L1StakingClaimedIterator struct { - Event *L1StakingClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingClaimed represents a Claimed event raised by the L1Staking contract. -type L1StakingClaimed struct { - Staker common.Address - Receiver common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterClaimed is a free log retrieval operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) FilterClaimed(opts *bind.FilterOpts, staker []common.Address) (*L1StakingClaimedIterator, error) { - - var stakerRule []interface{} - for _, stakerItem := range staker { - stakerRule = append(stakerRule, stakerItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Claimed", stakerRule) - if err != nil { - return nil, err - } - return &L1StakingClaimedIterator{contract: _L1Staking.contract, event: "Claimed", logs: logs, sub: sub}, nil -} - -// WatchClaimed is a free log subscription operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) WatchClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingClaimed, staker []common.Address) (event.Subscription, error) { - - var stakerRule []interface{} - for _, stakerItem := range staker { - stakerRule = append(stakerRule, stakerItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Claimed", stakerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseClaimed is a log parse operation binding the contract event 0x89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b. -// -// Solidity: event Claimed(address indexed staker, address receiver) -func (_L1Staking *L1StakingFilterer) ParseClaimed(log types.Log) (*L1StakingClaimed, error) { - event := new(L1StakingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "Claimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingGasLimitAddStakerUpdatedIterator is returned from FilterGasLimitAddStakerUpdated and is used to iterate over the raw logs and unpacked data for GasLimitAddStakerUpdated events raised by the L1Staking contract. -type L1StakingGasLimitAddStakerUpdatedIterator struct { - Event *L1StakingGasLimitAddStakerUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitAddStakerUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitAddStakerUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingGasLimitAddStakerUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingGasLimitAddStakerUpdated represents a GasLimitAddStakerUpdated event raised by the L1Staking contract. -type L1StakingGasLimitAddStakerUpdated struct { - OldGasLimit *big.Int - NewGasLimit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterGasLimitAddStakerUpdated is a free log retrieval operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) FilterGasLimitAddStakerUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitAddStakerUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitAddStakerUpdated") - if err != nil { - return nil, err - } - return &L1StakingGasLimitAddStakerUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitAddStakerUpdated", logs: logs, sub: sub}, nil -} - -// WatchGasLimitAddStakerUpdated is a free log subscription operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) WatchGasLimitAddStakerUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitAddStakerUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitAddStakerUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingGasLimitAddStakerUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseGasLimitAddStakerUpdated is a log parse operation binding the contract event 0x0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c. -// -// Solidity: event GasLimitAddStakerUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) ParseGasLimitAddStakerUpdated(log types.Log) (*L1StakingGasLimitAddStakerUpdated, error) { - event := new(L1StakingGasLimitAddStakerUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitAddStakerUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingGasLimitRemoveStakersUpdatedIterator is returned from FilterGasLimitRemoveStakersUpdated and is used to iterate over the raw logs and unpacked data for GasLimitRemoveStakersUpdated events raised by the L1Staking contract. -type L1StakingGasLimitRemoveStakersUpdatedIterator struct { - Event *L1StakingGasLimitRemoveStakersUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitRemoveStakersUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingGasLimitRemoveStakersUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingGasLimitRemoveStakersUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingGasLimitRemoveStakersUpdated represents a GasLimitRemoveStakersUpdated event raised by the L1Staking contract. -type L1StakingGasLimitRemoveStakersUpdated struct { - OldGasLimit *big.Int - NewGasLimit *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterGasLimitRemoveStakersUpdated is a free log retrieval operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) FilterGasLimitRemoveStakersUpdated(opts *bind.FilterOpts) (*L1StakingGasLimitRemoveStakersUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "GasLimitRemoveStakersUpdated") - if err != nil { - return nil, err - } - return &L1StakingGasLimitRemoveStakersUpdatedIterator{contract: _L1Staking.contract, event: "GasLimitRemoveStakersUpdated", logs: logs, sub: sub}, nil -} - -// WatchGasLimitRemoveStakersUpdated is a free log subscription operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) WatchGasLimitRemoveStakersUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingGasLimitRemoveStakersUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "GasLimitRemoveStakersUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingGasLimitRemoveStakersUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseGasLimitRemoveStakersUpdated is a log parse operation binding the contract event 0xdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7. -// -// Solidity: event GasLimitRemoveStakersUpdated(uint256 oldGasLimit, uint256 newGasLimit) -func (_L1Staking *L1StakingFilterer) ParseGasLimitRemoveStakersUpdated(log types.Log) (*L1StakingGasLimitRemoveStakersUpdated, error) { - event := new(L1StakingGasLimitRemoveStakersUpdated) - if err := _L1Staking.contract.UnpackLog(event, "GasLimitRemoveStakersUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the L1Staking contract. -type L1StakingInitializedIterator struct { - Event *L1StakingInitialized // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingInitializedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingInitializedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingInitializedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingInitialized represents a Initialized event raised by the L1Staking contract. -type L1StakingInitialized struct { - Version uint8 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) FilterInitialized(opts *bind.FilterOpts) (*L1StakingInitializedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return &L1StakingInitializedIterator{contract: _L1Staking.contract, event: "Initialized", logs: logs, sub: sub}, nil -} - -// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *L1StakingInitialized) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingInitialized) - if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_L1Staking *L1StakingFilterer) ParseInitialized(log types.Log) (*L1StakingInitialized, error) { - event := new(L1StakingInitialized) - if err := _L1Staking.contract.UnpackLog(event, "Initialized", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the L1Staking contract. -type L1StakingOwnershipTransferredIterator struct { - Event *L1StakingOwnershipTransferred // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingOwnershipTransferredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingOwnershipTransferredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingOwnershipTransferred represents a OwnershipTransferred event raised by the L1Staking contract. -type L1StakingOwnershipTransferred struct { - PreviousOwner common.Address - NewOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*L1StakingOwnershipTransferredIterator, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return &L1StakingOwnershipTransferredIterator{contract: _L1Staking.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *L1StakingOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingOwnershipTransferred) - if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) -func (_L1Staking *L1StakingFilterer) ParseOwnershipTransferred(log types.Log) (*L1StakingOwnershipTransferred, error) { - event := new(L1StakingOwnershipTransferred) - if err := _L1Staking.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingRegisteredIterator is returned from FilterRegistered and is used to iterate over the raw logs and unpacked data for Registered events raised by the L1Staking contract. -type L1StakingRegisteredIterator struct { - Event *L1StakingRegistered // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingRegisteredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingRegisteredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingRegisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingRegistered represents a Registered event raised by the L1Staking contract. -type L1StakingRegistered struct { - Addr common.Address - TmKey [32]byte - BlsKey []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRegistered is a free log retrieval operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) FilterRegistered(opts *bind.FilterOpts) (*L1StakingRegisteredIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Registered") - if err != nil { - return nil, err - } - return &L1StakingRegisteredIterator{contract: _L1Staking.contract, event: "Registered", logs: logs, sub: sub}, nil -} - -// WatchRegistered is a free log subscription operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) WatchRegistered(opts *bind.WatchOpts, sink chan<- *L1StakingRegistered) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Registered") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingRegistered) - if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRegistered is a log parse operation binding the contract event 0xb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199. -// -// Solidity: event Registered(address addr, bytes32 tmKey, bytes blsKey) -func (_L1Staking *L1StakingFilterer) ParseRegistered(log types.Log) (*L1StakingRegistered, error) { - event := new(L1StakingRegistered) - if err := _L1Staking.contract.UnpackLog(event, "Registered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the L1Staking contract. -type L1StakingRewardPercentageUpdatedIterator struct { - Event *L1StakingRewardPercentageUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingRewardPercentageUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingRewardPercentageUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingRewardPercentageUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingRewardPercentageUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the L1Staking contract. -type L1StakingRewardPercentageUpdated struct { - OldPercentage *big.Int - NewPercentage *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*L1StakingRewardPercentageUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return &L1StakingRewardPercentageUpdatedIterator{contract: _L1Staking.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil -} - -// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingRewardPercentageUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "RewardPercentageUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingRewardPercentageUpdated) - if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. -// -// Solidity: event RewardPercentageUpdated(uint256 oldPercentage, uint256 newPercentage) -func (_L1Staking *L1StakingFilterer) ParseRewardPercentageUpdated(log types.Log) (*L1StakingRewardPercentageUpdated, error) { - event := new(L1StakingRewardPercentageUpdated) - if err := _L1Staking.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the L1Staking contract. -type L1StakingSlashRemainingClaimedIterator struct { - Event *L1StakingSlashRemainingClaimed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingSlashRemainingClaimedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashRemainingClaimed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingSlashRemainingClaimedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingSlashRemainingClaimedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the L1Staking contract. -type L1StakingSlashRemainingClaimed struct { - Receiver common.Address - Amount *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts) (*L1StakingSlashRemainingClaimedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "SlashRemainingClaimed") - if err != nil { - return nil, err - } - return &L1StakingSlashRemainingClaimedIterator{contract: _L1Staking.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil -} - -// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashRemainingClaimed) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "SlashRemainingClaimed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingSlashRemainingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. -// -// Solidity: event SlashRemainingClaimed(address receiver, uint256 amount) -func (_L1Staking *L1StakingFilterer) ParseSlashRemainingClaimed(log types.Log) (*L1StakingSlashRemainingClaimed, error) { - event := new(L1StakingSlashRemainingClaimed) - if err := _L1Staking.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the L1Staking contract. -type L1StakingSlashedIterator struct { - Event *L1StakingSlashed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingSlashedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingSlashed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingSlashedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingSlashedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingSlashed represents a Slashed event raised by the L1Staking contract. -type L1StakingSlashed struct { - Stakers []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSlashed is a free log retrieval operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) FilterSlashed(opts *bind.FilterOpts) (*L1StakingSlashedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Slashed") - if err != nil { - return nil, err - } - return &L1StakingSlashedIterator{contract: _L1Staking.contract, event: "Slashed", logs: logs, sub: sub}, nil -} - -// WatchSlashed is a free log subscription operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *L1StakingSlashed) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Slashed") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingSlashed) - if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSlashed is a log parse operation binding the contract event 0x654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a. -// -// Solidity: event Slashed(address[] stakers) -func (_L1Staking *L1StakingFilterer) ParseSlashed(log types.Log) (*L1StakingSlashed, error) { - event := new(L1StakingSlashed) - if err := _L1Staking.contract.UnpackLog(event, "Slashed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingStakersRemovedIterator is returned from FilterStakersRemoved and is used to iterate over the raw logs and unpacked data for StakersRemoved events raised by the L1Staking contract. -type L1StakingStakersRemovedIterator struct { - Event *L1StakingStakersRemoved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingStakersRemovedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingStakersRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingStakersRemoved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingStakersRemovedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingStakersRemovedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingStakersRemoved represents a StakersRemoved event raised by the L1Staking contract. -type L1StakingStakersRemoved struct { - Stakers []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStakersRemoved is a free log retrieval operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) FilterStakersRemoved(opts *bind.FilterOpts) (*L1StakingStakersRemovedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakersRemoved") - if err != nil { - return nil, err - } - return &L1StakingStakersRemovedIterator{contract: _L1Staking.contract, event: "StakersRemoved", logs: logs, sub: sub}, nil -} - -// WatchStakersRemoved is a free log subscription operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) WatchStakersRemoved(opts *bind.WatchOpts, sink chan<- *L1StakingStakersRemoved) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakersRemoved") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingStakersRemoved) - if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStakersRemoved is a log parse operation binding the contract event 0x3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c84. -// -// Solidity: event StakersRemoved(address[] stakers) -func (_L1Staking *L1StakingFilterer) ParseStakersRemoved(log types.Log) (*L1StakingStakersRemoved, error) { - event := new(L1StakingStakersRemoved) - if err := _L1Staking.contract.UnpackLog(event, "StakersRemoved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingStakingValueUpdatedIterator is returned from FilterStakingValueUpdated and is used to iterate over the raw logs and unpacked data for StakingValueUpdated events raised by the L1Staking contract. -type L1StakingStakingValueUpdatedIterator struct { - Event *L1StakingStakingValueUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingStakingValueUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingStakingValueUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingStakingValueUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingStakingValueUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingStakingValueUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingStakingValueUpdated represents a StakingValueUpdated event raised by the L1Staking contract. -type L1StakingStakingValueUpdated struct { - OldStakingValue *big.Int - NewStakingValue *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterStakingValueUpdated is a free log retrieval operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) FilterStakingValueUpdated(opts *bind.FilterOpts) (*L1StakingStakingValueUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "StakingValueUpdated") - if err != nil { - return nil, err - } - return &L1StakingStakingValueUpdatedIterator{contract: _L1Staking.contract, event: "StakingValueUpdated", logs: logs, sub: sub}, nil -} - -// WatchStakingValueUpdated is a free log subscription operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) WatchStakingValueUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingStakingValueUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "StakingValueUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingStakingValueUpdated) - if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseStakingValueUpdated is a log parse operation binding the contract event 0x91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de74368. -// -// Solidity: event StakingValueUpdated(uint256 oldStakingValue, uint256 newStakingValue) -func (_L1Staking *L1StakingFilterer) ParseStakingValueUpdated(log types.Log) (*L1StakingStakingValueUpdated, error) { - event := new(L1StakingStakingValueUpdated) - if err := _L1Staking.contract.UnpackLog(event, "StakingValueUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingWhitelistUpdatedIterator is returned from FilterWhitelistUpdated and is used to iterate over the raw logs and unpacked data for WhitelistUpdated events raised by the L1Staking contract. -type L1StakingWhitelistUpdatedIterator struct { - Event *L1StakingWhitelistUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingWhitelistUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingWhitelistUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingWhitelistUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingWhitelistUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingWhitelistUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingWhitelistUpdated represents a WhitelistUpdated event raised by the L1Staking contract. -type L1StakingWhitelistUpdated struct { - Add []common.Address - Remove []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWhitelistUpdated is a free log retrieval operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) FilterWhitelistUpdated(opts *bind.FilterOpts) (*L1StakingWhitelistUpdatedIterator, error) { - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "WhitelistUpdated") - if err != nil { - return nil, err - } - return &L1StakingWhitelistUpdatedIterator{contract: _L1Staking.contract, event: "WhitelistUpdated", logs: logs, sub: sub}, nil -} - -// WatchWhitelistUpdated is a free log subscription operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) WatchWhitelistUpdated(opts *bind.WatchOpts, sink chan<- *L1StakingWhitelistUpdated) (event.Subscription, error) { - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "WhitelistUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingWhitelistUpdated) - if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWhitelistUpdated is a log parse operation binding the contract event 0xe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac8622. -// -// Solidity: event WhitelistUpdated(address[] add, address[] remove) -func (_L1Staking *L1StakingFilterer) ParseWhitelistUpdated(log types.Log) (*L1StakingWhitelistUpdated, error) { - event := new(L1StakingWhitelistUpdated) - if err := _L1Staking.contract.UnpackLog(event, "WhitelistUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// L1StakingWithdrawnIterator is returned from FilterWithdrawn and is used to iterate over the raw logs and unpacked data for Withdrawn events raised by the L1Staking contract. -type L1StakingWithdrawnIterator struct { - Event *L1StakingWithdrawn // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *L1StakingWithdrawnIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(L1StakingWithdrawn) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(L1StakingWithdrawn) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *L1StakingWithdrawnIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *L1StakingWithdrawnIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// L1StakingWithdrawn represents a Withdrawn event raised by the L1Staking contract. -type L1StakingWithdrawn struct { - Addr common.Address - UnlockHeight *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawn is a free log retrieval operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) FilterWithdrawn(opts *bind.FilterOpts, addr []common.Address) (*L1StakingWithdrawnIterator, error) { - - var addrRule []interface{} - for _, addrItem := range addr { - addrRule = append(addrRule, addrItem) - } - - logs, sub, err := _L1Staking.contract.FilterLogs(opts, "Withdrawn", addrRule) - if err != nil { - return nil, err - } - return &L1StakingWithdrawnIterator{contract: _L1Staking.contract, event: "Withdrawn", logs: logs, sub: sub}, nil -} - -// WatchWithdrawn is a free log subscription operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) WatchWithdrawn(opts *bind.WatchOpts, sink chan<- *L1StakingWithdrawn, addr []common.Address) (event.Subscription, error) { - - var addrRule []interface{} - for _, addrItem := range addr { - addrRule = append(addrRule, addrItem) - } - - logs, sub, err := _L1Staking.contract.WatchLogs(opts, "Withdrawn", addrRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(L1StakingWithdrawn) - if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawn is a log parse operation binding the contract event 0x7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5. -// -// Solidity: event Withdrawn(address indexed addr, uint256 unlockHeight) -func (_L1Staking *L1StakingFilterer) ParseWithdrawn(log types.Log) (*L1StakingWithdrawn, error) { - event := new(L1StakingWithdrawn) - if err := _L1Staking.contract.UnpackLog(event, "Withdrawn", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/bindings/bindings/l1staking_more.go b/bindings/bindings/l1staking_more.go deleted file mode 100644 index c3a973380..000000000 --- a/bindings/bindings/l1staking_more.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "encoding/json" - - "morph-l2/bindings/solc" -) - -const L1StakingStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1027_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1026_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakingValue\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawalLockBlocks\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitAddStaker\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"gasLimitRemoveStakers\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_uint256\"},{\"astId\":1013,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"whitelist\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"removedList\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerSet\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_address)1025_storage\"},{\"astId\":1017,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakerIndexes\",\"offset\":0,\"slot\":\"415\",\"type\":\"t_mapping(t_address,t_uint8)\"},{\"astId\":1018,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteList\",\"offset\":0,\"slot\":\"416\",\"type\":\"t_array(t_address)dyn_storage\"},{\"astId\":1019,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"deleteableHeight\",\"offset\":0,\"slot\":\"417\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1020,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"stakers\",\"offset\":0,\"slot\":\"418\",\"type\":\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"blsKeys\",\"offset\":0,\"slot\":\"419\",\"type\":\"t_mapping(t_bytes_memory_ptr,t_bool)\"},{\"astId\":1022,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"tmKeys\",\"offset\":0,\"slot\":\"420\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1023,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"withdrawals\",\"offset\":0,\"slot\":\"421\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1024,\"contract\":\"contracts/l1/staking/L1Staking.sol:L1Staking\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"422\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_address)1025_storage\":{\"encoding\":\"inplace\",\"label\":\"address[255]\",\"numberOfBytes\":\"8160\"},\"t_array(t_address)dyn_storage\":{\"encoding\":\"dynamic_array\",\"label\":\"address[]\",\"numberOfBytes\":\"32\"},\"t_array(t_uint256)1026_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1027_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_bytes_memory_ptr\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_bytes_storage\":{\"encoding\":\"bytes\",\"label\":\"bytes\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_struct(StakerInfo)1028_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e struct Types.StakerInfo)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_struct(StakerInfo)1028_storage\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_address,t_uint8)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint8)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint8\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_bytes_memory_ptr,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes_memory_ptr\",\"value\":\"t_bool\"},\"t_struct(StakerInfo)1028_storage\":{\"encoding\":\"inplace\",\"label\":\"struct Types.StakerInfo\",\"numberOfBytes\":\"96\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" - -var L1StakingStorageLayout = new(solc.StorageLayout) - -var L1StakingDeployedBin = "0x6080604052600436106102f8575f3560e01c80637a9262a211610191578063ab8c53dc116100dc578063d51c90a911610087578063e2a6ad5f11610062578063e2a6ad5f14610940578063f2fde38b1461095f578063f4fe7fef1461097e575f80fd5b8063d51c90a9146108a6578063dd4785f5146108bb578063df155033146108fc575f80fd5b8063c7cd469a116100b7578063c7cd469a14610849578063cde4cd1114610868578063d096c3c614610887575f80fd5b8063ab8c53dc146107e9578063ae81de53146107fe578063bfa02ba91461081d575f80fd5b8063927ede2d1161013c5780639fb82db9116101175780639fb82db914610797578063a3066aab146107ab578063a4f209b0146107ca575f80fd5b8063927ede2d1461070a5780639b19251a1461073d5780639d48f4171461076b575f80fd5b80638a565ac31161016c5780638a565ac3146106935780638da5cb5b146106b25780639168ae72146106dc575f80fd5b80637a9262a2146106155780638142951a14610641578063831cfb5814610660575f80fd5b806341de239b11610251578063692c565b116101fc57806374fe27b7116101d757806374fe27b714610595578063797adbde146105bb5780637a4e87c3146105da575f80fd5b8063692c565b146105335780636f1e853314610562578063715018a614610581575f80fd5b80634d64903a1161022c5780634d64903a146104ea57806352d472eb146104ff5780636801579114610514575f80fd5b806341de239b1461049557806343352d61146104aa57806345bc4d10146104cb575f80fd5b8063320ff860116102b15780633cb747bf1161028c5780633cb747bf1461043b5780633ccfd60b1461046d5780633ee2a1f914610481575f80fd5b8063320ff860146103bf57806335928991146103de5780633a9bbede146103fd575f80fd5b80632a28e5a3116102e15780632a28e5a31461033a5780632e407a6f1461034f578063303afb9e1461037b575f80fd5b80630d13fd7b146102fc5780632108db3514610325575b5f80fd5b348015610307575f80fd5b506103126101a65481565b6040519081526020015b60405180910390f35b348015610330575f80fd5b50610312609c5481565b61034d610348366004613d4e565b61099d565b005b34801561035a575f80fd5b50610312610369366004613db5565b6101a16020525f908152604090205481565b348015610386575f80fd5b5061039a610395366004613dd5565b610e5f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031c565b3480156103ca575f80fd5b5061034d6103d9366004613dec565b610e8b565b3480156103e9575f80fd5b5061034d6103f8366004613dd5565b61127a565b348015610408575f80fd5b5061042b610417366004613db5565b609f6020525f908152604090205460ff1681565b604051901515815260200161031c565b348015610446575f80fd5b507f000000000000000000000000000000000000000000000000000000000000000061039a565b348015610478575f80fd5b5061034d611341565b34801561048c575f80fd5b5061034d611579565b3480156104a0575f80fd5b5061031260995481565b3480156104b5575f80fd5b506104be61158b565b60405161031c9190613e94565b3480156104d6575f80fd5b506103126104e5366004613dd5565b6115de565b3480156104f5575f80fd5b5061031260985481565b34801561050a575f80fd5b50610312609a5481565b34801561051f575f80fd5b5061042b61052e366004613db5565b61199a565b34801561053e575f80fd5b5061042b61054d366004613dd5565b6101a46020525f908152604090205460ff1681565b34801561056d575f80fd5b5061042b61057c366004613db5565b611a69565b34801561058c575f80fd5b5061034d611b09565b3480156105a0575f80fd5b5061042b6105af366004613f23565b60019695505050505050565b3480156105c6575f80fd5b5061039a6105d5366004613dd5565b611b1a565b3480156105e5575f80fd5b5061042b6105f4366004613fc9565b80516020818301810180516101a38252928201919093012091525460ff1681565b348015610620575f80fd5b5061031261062f366004613db5565b6101a56020525f908152604090205481565b34801561064c575f80fd5b5061034d61065b366004614003565b611b50565b34801561066b575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069e575f80fd5b5061034d6106ad366004613dd5565b61211a565b3480156106bd575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661039a565b3480156106e7575f80fd5b506106fb6106f6366004613db5565b6121d7565b60405161031c939291906140bc565b348015610715575f80fd5b5061039a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610748575f80fd5b5061042b610757366004613db5565b609e6020525f908152604090205460ff1681565b348015610776575f80fd5b5061078a610785366004613dd5565b612297565b60405161031c91906140f9565b3480156107a2575f80fd5b5061078a6123ce565b3480156107b6575f80fd5b5061034d6107c5366004613db5565b6125b0565b3480156107d5575f80fd5b5061034d6107e4366004613dd5565b612721565b3480156107f4575f80fd5b50610312609d5481565b348015610809575f80fd5b5061034d610818366004613dd5565b6127eb565b348015610828575f80fd5b5060975461039a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610854575f80fd5b5061034d610863366004614152565b6128a8565b348015610873575f80fd5b5061034d610882366004613db5565b612ac6565b348015610892575f80fd5b506103126108a1366004613db5565b612b41565b3480156108b1575f80fd5b50610312609b5481565b3480156108c6575f80fd5b506108ea6108d5366004613db5565b61019f6020525f908152604090205460ff1681565b60405160ff909116815260200161031c565b348015610907575f80fd5b5061042b610916366004613db5565b73ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b34801561094b575f80fd5b5061031261095a3660046141b9565b612be2565b34801561096a575f80fd5b5061034d610979366004613db5565b612d55565b348015610989575f80fd5b5061034d610998366004613dd5565b612e09565b335f818152609e602052604090205460ff16610a1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420696e2077686974656c6973740000000000000000000000000000000060448201526064015b60405180910390fd5b335f9081526101a2602052604090205473ffffffffffffffffffffffffffffffffffffffff1615610aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f616c7265616479207265676973746572656400000000000000000000000000006044820152606401610a11565b8215801590610ac557505f8381526101a4602052604090205460ff16155b610b2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c69642074656e6465726d696e74207075626b6579000000000000006044820152606401610a11565b8151610100148015610b5e57506101a382604051610b4991906141f8565b9081526040519081900360200190205460ff16155b610bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420626c73207075626b657900000000000000000000000000006044820152606401610a11565b6098543414610c2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b6040518060600160405280610c413390565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083018790526040928301869052335f9081526101a28252839020845181547fffffffffffffffffffffffff00000000000000000000000000000000000000001693169290921782558301516001820155908201516002820190610cc190826142a8565b50905050610cd4610ccf3390565b612ec6565b60016101a383604051610ce791906141f8565b9081526040805191829003602090810190922080549315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009485161790555f8681526101a49092529020805490911660011790557fb9c7babb56df9f2da4a30811a6c778e4e68af88b72712d56cf62c5516e20e199610d643390565b8484604051610d75939291906140bc565b60405180910390a1335f9081526101a260209081526040918290208251606081018452815473ffffffffffffffffffffffffffffffffffffffff168152600182015492810192909252600281018054610e5a9484019190610dd590614213565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0190614213565b8015610e4c5780601f10610e2357610100808354040283529160200191610e4c565b820191905f5260205f20905b815481529060010190602001808311610e2f57829003601f168201915b505050505081525050613033565b505050565b60a08160ff8110610e6e575f80fd5b015473ffffffffffffffffffffffffffffffffffffffff16905081565b610e93613186565b5f5b815181101561123657610ec0828281518110610eb357610eb36143c4565b602002602001015161199a565b610f4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f6f6e6c7920616374697665207374616b65722063616e2062652072656d6f766560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a11565b6101a55f838381518110610f6257610f626143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20545f1461100c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611019904361441e565b6101a55f84848151811061102f5761102f6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550611096828281518110611089576110896143c4565b6020026020010151613207565b8181815181106110a8576110a86143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d56101a55f8585815181106110fd576110fd6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205460405161114e91815260200190565b60405180910390a2609e5f83838151811061116b5761116b6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f8484815181106111d2576111d26143c4565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610e95565b507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b60405180910390a16112778161333a565b50565b611282613186565b5f8111801561129457506101a6548114155b6112fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b6101a680549082905560408051828152602081018490527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d5591015b60405180910390a15050565b61134a3361199a565b6113b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f6e6c7920616374697665207374616b657200000000000000000000000000006044820152606401610a11565b335f9081526101a5602052604090205415611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7769746864726177696e670000000000000000000000000000000000000000006044820152606401610a11565b609954611434904361441e565b335f8181526101a5602052604090209190915561145090613207565b335f8181526101a560209081526040918290205491519182527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5910160405180910390a2335f908152609e6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609f83528184208054909116600190811790915581518181528083019092529091828101908036833701905050905033815f81518110611510576115106143c4565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848160405161126691906140f9565b611581613186565b61158961345d565b565b611593613bdf565b60408051611fe08101918290529060a09060ff9082845b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116115aa575050505050905090565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610a11565b61167f6137ae565b5f61168983612297565b90505f805b82518110156118b0575f6101a55f8584815181106116ae576116ae6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541115611765576101a55f84838151811061170c5761170c6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f90556098548261175e919061441e565b91506118a8565b6117ac83828151811061177a5761177a6143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff165f9081526101a16020526040902054151590565b6118a8576098546117bd908361441e565b91506117d4838281518110611089576110896143c4565b609e5f8483815181106117e9576117e96143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81549060ff02191690556001609f5f858481518110611850576118506143c4565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055505b60010161168e565b505f6064609a54836118c29190614431565b6118cc9190614448565b90506118d88183614480565b609d5f8282546118e8919061441e565b90915550506097546119109073ffffffffffffffffffffffffffffffffffffffff1682613821565b7f654f4a61849f1b3ad10abb283d27f02d5fece7b820acc5a3b874713b58748b5a8360405161193f91906140f9565b60405180910390a17f3f446646c03e618be8238a586960d6d625f35c653cdca1ef59609993e8ed2c848360405161197691906140f9565b60405180910390a16119878361333a565b925050506119956001606555565b919050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff1681036119d057505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611a089060019060ff16614493565b60ff1660ff8110611a1b57611a1b6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16148015611a63575073ffffffffffffffffffffffffffffffffffffffff82165f9081526101a16020526040902054155b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815261019f602052604081205460ff168103611a9f57505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f81815261019f602052604090205460a090611ad79060019060ff16614493565b60ff1660ff8110611aea57611aea6143c4565b015473ffffffffffffffffffffffffffffffffffffffff161492915050565b611b11613186565b6115895f6138f8565b6101a08181548110611b2a575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b5f54610100900460ff1615808015611b6e57505f54600160ff909116105b80611b875750303b158015611b8757505f5460ff166001145b611c13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a11565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611c6f575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8816611cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610a11565b5f8711611d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b5f8611611dbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206368616c6c656e6765206465706f7369742076616c7565006044820152606401610a11565b5f8511611e27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c6964207769746864726177616c206c6f636b20626c6f636b7300006044820152606401610a11565b5f8311611e90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420676173206c696d697420616464207374616b6572000000006044820152606401610a11565b5f8211611ef9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e76616c696420676173206c696d69742072656d6f7665207374616b6572736044820152606401610a11565b5f84118015611f09575060648411155b611f94576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f696e76616c6964206368616c6c656e676572207265776172642070657263656e60448201527f74616765000000000000000000000000000000000000000000000000000000006064820152608401610a11565b611f9c61396e565b611fa4613a0c565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a16179055609a84905560988790556101a68690556099859055609b839055609c829055604080515f8152602081018590527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c910160405180910390a1604080515f8152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f7910160405180910390a1604080515f8152602081018690527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a18015612110575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b612122613186565b5f811180156121335750609c548114155b612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609c80549082905560408051828152602081018490527fdd4b37d1f14888147fe4be2cfaedcbf148fd07ececc856d0433241b8b6e4a7f79101611335565b6101a26020525f908152604090208054600182015460028301805473ffffffffffffffffffffffffffffffffffffffff90931693919261221690614213565b80601f016020809104026020016040519081016040528092919081815260200182805461224290614213565b801561228d5780601f106122645761010080835404028352916020019161228d565b820191905f5260205f20905b81548152906001019060200180831161227057829003601f168201915b5050505050905083565b6060600182901c5f5b81156122c7576122b181600161441e565b90506122be600183614480565b821691506122a0565b8067ffffffffffffffff8111156122e0576122e0613c48565b604051908082528060200260200182016040528015612309578160200160208202803683370190505b5092505f60015b60ff8160ff16116123c557600160ff82161b8616156123b35760a0612336600183614493565b60ff1660ff8110612349576123496143c4565b0154855173ffffffffffffffffffffffffffffffffffffffff90911690869084908110612378576123786143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526123a882600161441e565b9150828210156123c5575b806123bd816144ac565b915050612310565b50505050919050565b6040805160ff80825261200082019092526060915f91829160208201611fe0803683370190505090505f5b60ff8110156124b7575f60a08260ff8110612416576124166143c4565b015473ffffffffffffffffffffffffffffffffffffffff161480159061247857506101a15f60a08360ff811061244e5761244e6143c4565b015473ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054155b156124af5782612487816144ca565b935050600182828151811061249e5761249e6143c4565b911515602092830291909101909101525b6001016123f9565b505f8267ffffffffffffffff8111156124d2576124d2613c48565b6040519080825280602002602001820160405280156124fb578160200160208202803683370190505b5090505f805b60ff8110156125a65783818151811061251c5761251c6143c4565b60200260200101511561259e5760a08160ff811061253c5761253c6143c4565b0154835173ffffffffffffffffffffffffffffffffffffffff9091169084908490811061256b5761256b6143c4565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528161259a816144ca565b9250505b600101612501565b5090949350505050565b6125b86137ae565b335f9081526101a5602052604090205461262e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7769746864726177616c206e6f742065786973740000000000000000000000006044820152606401610a11565b335f9081526101a560205260409020544310156126a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f7769746864726177616c206c6f636b65640000000000000000000000000000006044820152606401610a11565b335f9081526101a560205260408120556126bf61345d565b6040805173ffffffffffffffffffffffffffffffffffffffff83168152905133917f89309c9b2aeaffbdce717113df9427298b20448c05919bf889e05f8c3094254b919081900360200190a261271781609854613821565b6112776001606555565b612729613186565b5f81118015612739575060648111155b80156127475750609a548114155b6127ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610a11565b609a80549082905560408051828152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba9101611335565b6127f3613186565b5f811180156128045750609b548114155b61286a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206e657720676173206c696d697400000000000000000000006044820152606401610a11565b609b80549082905560408051828152602081018490527f0ef80fb82bf5439b8591744c0fde771f5d93dce7a7970b1e9b7828cdc3970e9c9101611335565b6128b0613186565b5f5b838110156129fa57609f5f8686848181106128cf576128cf6143c4565b90506020020160208101906128e49190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f205460ff1615612974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e2072656d6f766564206c69737400000000000000000000000000000000006044820152606401610a11565b6001609e5f87878581811061298b5761298b6143c4565b90506020020160208101906129a09190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556001016128b2565b505f5b81811015612a8257609e5f848484818110612a1a57612a1a6143c4565b9050602002016020810190612a2f9190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001016129fd565b507fe375867e538b40218c1b3db2ccceaf875eb073e38b510449e6088c1539ac862284848484604051612ab89493929190614553565b60405180910390a150505050565b612ace613186565b612ad66137ae565b609d54612ae38282613821565b5f609d556040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9910160405180910390a1506112776001606555565b5f612b4b82611a69565b612bb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b5073ffffffffffffffffffffffffffffffffffffffff165f90815261019f6020526040902054600160ff9091161b90565b5f60ff821115612c4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7374616b657273206c656e677468206f7574206f6620626f756e6473000000006044820152606401610a11565b5f5b82811015612d4e57612c82848483818110612c6d57612c6d6143c4565b905060200201602081019061057c9190613db5565b612ce8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c6964207374616b65720000000000000000000000000000000000006044820152606401610a11565b61019f5f858584818110612cfe57612cfe6143c4565b9050602002016020810190612d139190613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2054600160ff90911681901b929092179101612c50565b5092915050565b612d5d613186565b73ffffffffffffffffffffffffffffffffffffffff8116612e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a11565b611277816138f8565b612e11613186565b5f81118015612e2257506098548114155b612e88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964207374616b696e672076616c756500000000000000000000006044820152606401610a11565b609880549082905560408051828152602081018490527f91e3ed304d49776a78bbe0df6bf7156f5433763621e5e728a3c2adfe7de743689101611335565b5f5b60ff8160ff161015612fd0575f60a060ff808416908110612eeb57612eeb6143c4565b015473ffffffffffffffffffffffffffffffffffffffff1603612fc8578160a08260ff1660ff8110612f1f57612f1f6143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055612f6e816001614584565b73ffffffffffffffffffffffffffffffffffffffff929092165f90815261019f6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff9093169290921790915550565b600101612ec8565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f736c6f742066756c6c00000000000000000000000000000000000000000000006044820152606401610a11565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016130a2919061459d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6d454d5100000000000000000000000000000000000000000000000000000000179052609b5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f604051808303815f87803b15801561316d575f80fd5b505af115801561317f573d5f803e3d5ffd5b5050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314611589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a11565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526101a1602052604090205415613294576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f616c726561647920696e2064656c6574654c69737400000000000000000000006044820152606401610a11565b6101a080546001810182555f919091527f7980fe0f714a613298681d64b7b8ffa7b148338dd52429f307d72798d5c317c40180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316179055609954613311904361441e565b73ffffffffffffffffffffffffffffffffffffffff9091165f9081526101a16020526040902055565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b2267a7b7f00000000000000000000000000000000000000000000000000000000000000005f846040516024016133a991906140f9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0be67fcc00000000000000000000000000000000000000000000000000000000179052609c5490517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261315694939291906004016145e1565b5f5b6101a05481101561127757436101a15f6101a08481548110613483576134836143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020541161379c5760a0600161019f5f6101a085815481106134d5576134d56143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054613513919060ff16614493565b60ff1660ff8110613526576135266143c4565b0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556101a0805461019f915f9184908110613568576135686143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556101a080546101a2929190849081106135d9576135d96143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560018101829055906136446002830182613bfe565b50506101a15f6101a0838154811061365e5761365e6143c4565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040018120556101a080546136a090600190614480565b815481106136b0576136b06143c4565b5f918252602090912001546101a0805473ffffffffffffffffffffffffffffffffffffffff90921691839081106136e9576136e96143c4565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101a080548061374057613740614626565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905561345f565b806137a6816144ca565b91505061345f565b60026065540361381a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a11565b6002606555565b80156138ed575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461387d576040519150601f19603f3d011682016040523d82523d5f602084013e613882565b606091505b5050905080610e5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610a11565b5050565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16613a04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613aaa565b5f54610100900460ff16613aa2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589613b49565b5f54610100900460ff16613b40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b611589336138f8565b5f54610100900460ff166138f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a11565b60405180611fe0016040528060ff906020820280368337509192915050565b508054613c0a90614213565b5f825580601f10613c19575050565b601f0160209004905f5260205f209081019061127791905b80821115613c44575f8155600101613c31565b5090565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613cbc57613cbc613c48565b604052919050565b5f82601f830112613cd3575f80fd5b813567ffffffffffffffff811115613ced57613ced613c48565b613d1e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613c75565b818152846020838601011115613d32575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613d5f575f80fd5b82359150602083013567ffffffffffffffff811115613d7c575f80fd5b613d8885828601613cc4565b9150509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611995575f80fd5b5f60208284031215613dc5575f80fd5b613dce82613d92565b9392505050565b5f60208284031215613de5575f80fd5b5035919050565b5f6020808385031215613dfd575f80fd5b823567ffffffffffffffff80821115613e14575f80fd5b818501915085601f830112613e27575f80fd5b813581811115613e3957613e39613c48565b8060051b9150613e4a848301613c75565b8181529183018401918481019088841115613e63575f80fd5b938501935b83851015613e8857613e7985613d92565b82529385019390850190613e68565b98975050505050505050565b611fe0810181835f5b60ff811015613ed257815173ffffffffffffffffffffffffffffffffffffffff16835260209283019290910190600101613e9d565b50505092915050565b5f8083601f840112613eeb575f80fd5b50813567ffffffffffffffff811115613f02575f80fd5b6020830191508360208260051b8501011115613f1c575f80fd5b9250929050565b5f805f805f8060808789031215613f38575f80fd5b86359550602087013567ffffffffffffffff80821115613f56575f80fd5b613f628a838b01613edb565b9097509550604089013594506060890135915080821115613f81575f80fd5b818901915089601f830112613f94575f80fd5b813581811115613fa2575f80fd5b8a6020828501011115613fb3575f80fd5b6020830194508093505050509295509295509295565b5f60208284031215613fd9575f80fd5b813567ffffffffffffffff811115613fef575f80fd5b613ffb84828501613cc4565b949350505050565b5f805f805f805f60e0888a031215614019575f80fd5b61402288613d92565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b5f5b8381101561406b578181015183820152602001614053565b50505f910152565b5f815180845261408a816020860160208601614051565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6140f06060830184614073565b95945050505050565b602080825282518282018190525f9190848201906040850190845b8181101561414657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614114565b50909695505050505050565b5f805f8060408587031215614165575f80fd5b843567ffffffffffffffff8082111561417c575f80fd5b61418888838901613edb565b909650945060208701359150808211156141a0575f80fd5b506141ad87828801613edb565b95989497509550505050565b5f80602083850312156141ca575f80fd5b823567ffffffffffffffff8111156141e0575f80fd5b6141ec85828601613edb565b90969095509350505050565b5f8251614209818460208701614051565b9190910192915050565b600181811c9082168061422757607f821691505b60208210810361425e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b601f821115610e5a57805f5260205f20601f840160051c810160208510156142895750805b601f840160051c820191505b8181101561317f575f8155600101614295565b815167ffffffffffffffff8111156142c2576142c2613c48565b6142d6816142d08454614213565b84614264565b602080601f831160018114614328575f84156142f25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556143bc565b5f858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561437457888601518255948401946001909101908401614355565b50858210156143b057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b505060018460011b0185555b505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611a6357611a636143f1565b8082028115828204841417611a6357611a636143f1565b5f8261447b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115611a6357611a636143f1565b60ff8281168282160390811115611a6357611a636143f1565b5f60ff821660ff81036144c1576144c16143f1565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036144fa576144fa6143f1565b5060010190565b8183525f60208085019450825f5b858110156145485773ffffffffffffffffffffffffffffffffffffffff61453583613d92565b168752958201959082019060010161450f565b509495945050505050565b604081525f614566604083018688614501565b8281036020840152614579818587614501565b979650505050505050565b60ff8181168382160190811115611a6357611a636143f1565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201525f6040830151606080840152613ffb6080840182614073565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201525f6146156080830185614073565b905082606083015295945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea164736f6c6343000818000a" - -func init() { - if err := json.Unmarshal([]byte(L1StakingStorageLayoutJSON), L1StakingStorageLayout); err != nil { - panic(err) - } - - layouts["L1Staking"] = L1StakingStorageLayout - deployedBytecodes["L1Staking"] = L1StakingDeployedBin -} diff --git a/bindings/bindings/rollup.go b/bindings/bindings/rollup.go index a3e5d0a88..832bffe8f 100644 --- a/bindings/bindings/rollup.go +++ b/bindings/bindings/rollup.go @@ -40,17 +40,10 @@ type IRollupBatchDataInput struct { WithdrawalRoot [32]byte } -// IRollupBatchSignatureInput is an auto generated low-level Go binding around an user-defined struct. -type IRollupBatchSignatureInput struct { - SignedSequencersBitmap *big.Int - SequencerSets []byte - Signature []byte -} - // RollupMetaData contains all meta data concerning the Rollup contract. var RollupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"signedSequencersBitmap\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"sequencerSets\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIRollup.BatchSignatureInput\",\"name\":\"batchSignatureInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1StakingContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1StakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a060405234801562000010575f80fd5b506040516200578d3803806200578d83398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b60805161562f6200015e5f395f81816106a20152614408015261562f5ff3fe608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610ac4578063e3fff1dd14610ad9578063f2fde38b14610af8578063fb1e8b0414610b17575f80fd5b8063d8dc99d214610a71578063ddd8a3dc14610a86578063de8b303514610aa5575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a0b578063ce5db8d614610a1e578063cf9a674514610a33578063d279c19114610a52575f80fd5b8063b8d0a1b0146109ae578063bedb86fb146109cd578063c5553892146109ec575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461093c578063b348442514610951578063b35dac4e14610970578063b3e0a5091461098f575f80fd5b8063a479265d146108dd578063a4f209b0146108f2578063abc8d68d14610911575f80fd5b80638f1d3776116101985780638f1d3776146107af578063910129d41461085f57806397fc007c14610890578063a415d8dc146108af575f80fd5b8063728cdbca1461075a57806388b1ea09146107795780638da5cb5b14610792575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e57806361267290146106dd57806368589dfa146106fc5780636c578c1d14610727578063715018a614610746575f80fd5b80635c975abb1461061a5780635ef7a94a146106315780635f77cf1d14610691575f80fd5b80633e001b661161026e5780633e001b66146105b4578063428868b5146105c95780634e8f1d67146105dc57806357e0af6c146105fb575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a14610595575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004614e13565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004614e40565b610b2c565b005b3480156103f0575f80fd5b506103e36103ff366004614e9e565b610bfe565b34801561040f575f80fd5b5061038c61041e366004614e13565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004614ee6565b610f3a565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004614e13565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004614f45565b611434565b3480156104c9575f80fd5b5061038c6104d8366004614e13565b61181f565b3480156104e8575f80fd5b506103b66104f7366004614e13565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004614e13565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004614e13565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610398565b3480156105a0575f80fd5b50609b5461057d906001600160a01b031681565b3480156105bf575f80fd5b506103b660aa5481565b6103e36105d7366004614f45565b61184d565b3480156105e7575f80fd5b506103e36105f6366004614fa5565b611be8565b348015610606575f80fd5b506103e3610615366004614e13565b611f9c565b348015610625575f80fd5b5060655460ff1661038c565b34801561063c575f80fd5b5061067161064b366004614e13565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b34801561069c575f80fd5b506106c47f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b3480156106e8575f80fd5b506103e36106f7366004614e13565b612047565b348015610707575f80fd5b506103b6610716366004614e13565b60ab6020525f908152604090205481565b348015610732575f80fd5b506103e3610741366004614e40565b612222565b348015610751575f80fd5b506103e36122df565b348015610765575f80fd5b506103e3610774366004615056565b6122f2565b348015610784575f80fd5b5060a65461038c9060ff1681565b34801561079d575f80fd5b506033546001600160a01b031661057d565b3480156107ba575f80fd5b5061081b6107c9366004614e13565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b34801561086a575f80fd5b5061038c610879366004614e13565b5f90815260a4602052604090206003015460ff1690565b34801561089b575f80fd5b506103e36108aa366004614e40565b6125fb565b3480156108ba575f80fd5b5061038c6108c9366004614e40565b609f6020525f908152604090205460ff1681565b3480156108e8575f80fd5b506103b660995481565b3480156108fd575f80fd5b506103e361090c366004614e13565b6126de565b34801561091c575f80fd5b506103b661092b366004614e40565b60a56020525f908152604090205481565b348015610947575f80fd5b506103b660a85481565b34801561095c575f80fd5b506103e361096b3660046150b1565b61278e565b34801561097b575f80fd5b506103e361098a366004614e40565b612a92565b34801561099a575f80fd5b506103e36109a9366004614ee6565b612aeb565b3480156109b9575f80fd5b506103e36109c83660046150b1565b612e48565b3480156109d8575f80fd5b506103e36109e7366004615125565b612ed1565b3480156109f7575f80fd5b506103e3610a06366004614e13565b61300f565b6103e3610a19366004615157565b6130b2565b348015610a29575f80fd5b506103b660985481565b348015610a3e575f80fd5b506103e3610a4d366004614e13565b613644565b348015610a5d575f80fd5b506103e3610a6c366004614e40565b6137b3565b348015610a7c575f80fd5b506103b660ac5481565b348015610a91575f80fd5b5060975461057d906001600160a01b031681565b348015610ab0575f80fd5b5061038c610abf366004614e13565b613872565b348015610acf575f80fd5b506103b6609a5481565b348015610ae4575f80fd5b506103e3610af3366004614e13565b6138bc565b348015610b03575f80fd5b506103e3610b12366004614e40565b61395f565b348015610b22575f80fd5b506103b660a95481565b610b346139ec565b6001600160a01b0381165f908152609f602052604090205460ff1615610ba15760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c066139ec565b5f8111610c555760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610b98565b5f80610c618585613a46565b915091505f610c74836001015160c01c90565b5f81815260a160205260409020549091508214610cd35760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f60a181610ce187856151ac565b81526020019081526020015f205414610d615760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610b98565b609d548111610dd85760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b610de36001826151bf565b609e555b8315610f3257604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e2f81613872565b15610e8a575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610e7a9084906151ac565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610eea575060a85481145b15610ef4575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610de7575b505050505050565b60a85415610f8a5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b610f92613aee565b5f80610f9e8484613a46565b915091505f610fb1836001015160c01c90565b5f81815260a1602052604090205490915082146110105760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6110198161181f565b6110655760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b61106e81613872565b156110bb5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a4602052604090206003015460ff161561111c5760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610b98565b5f81815260a2602052604090206001015442101561117c5760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610b98565b605983015160a05f61118f6001856151bf565b81526020019081526020015f2054146111ea5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f81815260a06020526040902054156112455760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610b98565b80609d54600101146112995760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b609d819055600160a35f6112ae866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a060205260409020556112fd6112f0846011015160c01c90565b600985015160c01c613b41565b60a25f61130b6001846151bf565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab919061134490846151bf565b81526020019081526020015f205f905560ad5f60018361136491906151bf565b81526020019081526020015f205f905560a45f60018361138491906151bf565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611410866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156114a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c491906151d2565b6115105760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156115605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611568613aee565b5f49156115b75760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610b98565b5f6115cd6115c860208501856151ed565b613a46565b5090505f6115df826001015160c01c90565b6115ea9060016151ac565b5f81815260ad602052604090205490915061166d5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156116d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f5919061524e565b6116ff91906151ac565b1015611767575f6117166080860160608701615265565b61ffff16116117675760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156117d5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f9919061524e565b905061181885858360ad5f8781526020019081526020015f2054613bfe565b5050505050565b5f81815260a260205260408120541580159061184757505f82815260a1602052604090205415155b92915050565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118dd91906151d2565b6119295760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b60a854156119795760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611981613aee565b5f6119926115c860208501856151ed565b5090505f6119a4826001015160c01c90565b6119af9060016151ac565b5f81815260ad602052604090205490915015611a335760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610b98565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611a97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abb919061524e565b611ac591906151ac565b1015611b2d575f611adc6080860160608701615265565b61ffff1611611b2d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b6097545f906001600160a01b031663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf919061524e565b90505f611bda611bd26020880188615286565b60ff1661425e565b9050610f3286868484613bfe565b60a85415611c385760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b611c40613aee565b60ac54609e545f90815260a2602052604081205490914291611c6291906151ac565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cde919061524e565b611ce891906151ac565b10905081158015611cf65750805b15611d5d575f611d0c60808a0160608b01615265565b61ffff1611611d5d5760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610b98565b8180611d665750805b611db25760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610b98565b5f611dc36115c860208b018b6151ed565b5090505f611dd5826001015160c01c90565b611de09060016151ac565b5f81815260ad60205260408120549192509015611e80575f4915611e6c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610b98565b505f81815260ad6020526040902054611e93565b611e90611bd260208d018d615286565b90505b611e9f8b8b5f84613bfe565b5f80611eab8b8b613a46565b915091505f611ebe836001015160c01c90565b905080609e5414611f115760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214611f6d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b5f81815260a26020526040902042600190910155611f8c838b8b614399565b5050505050505050505050505050565b611fa46139ec565b5f81118015611fb557506099548114155b6120015760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610b98565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561206757505f5460ff8083169116105b6120d95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001790556120f75f5460ff1690565b60ff166002146121495760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610b98565b816121bc5760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610b98565b609e545f90815260ab60205260409020546121e557609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b61222a6139ec565b6001600160a01b0381165f908152609f602052604090205460ff166122915760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610b98565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610bf3565b6122e76139ec565b6122f05f61454c565b565b5f54610100900460ff161580801561231057505f54600160ff909116105b806123295750303b15801561232957505f5460ff166001145b61239b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805460ff1916600117905580156123bc575f805461ff0019166101001790555b6001600160a01b03861615806123d957506001600160a01b038516155b15612410576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166124665760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610b98565b61246e6145b5565b612476614639565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a180156125f2575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6126036139ec565b6001600160a01b038116158015906126295750609c546001600160a01b03828116911614155b6126755760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610b98565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b6126e66139ec565b5f811180156126f6575060648111155b8015612704575060a9548114155b6127505760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610b98565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161203b565b60a854156127de5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b6127e6613aee565b6097546001600160a01b03166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612852573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061287691906151d2565b6128c25760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610b98565b5f806128ce8686613a46565b915091505f6128e1836001015160c01c90565b5f81815260a1602052604090205490915082146129405760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b61294981613872565b6129955760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610b98565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff1916905560995460029091015442916129d1916151ac565b11612a47575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612a42918391906146bd565b6125f2565b612a52838686614399565b6125f281336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250614819565b612a9a6139ec565b60aa80545f909155612aac82826148e5565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161203b565b612af36139ec565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612b6a5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610b98565b5f80612b768484613a46565b915091505f612b89836001015160c01c90565b90508015612bd95760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610b98565b5f612be5846079015190565b905080612c345760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610b98565b600984015160c01c15612c895760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610b98565b5f612c95856019015190565b03612ce25760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610b98565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612d0e856039015190565b14612d5b5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610b98565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612e548686613a46565b915091505f612e67836001015160c01c90565b5f81815260a160205260409020549091508214612ec65760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6125f2838686614399565b612ed96139ec565b8015612fdd57612ee7614990565b60a65460ff1615612f9c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612f3b9084906151ac565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612fe56149ea565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612fbf565b50565b6130176139ec565b5f81118015613028575060ac548114155b6130745760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610b98565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161203b565b335f908152609f602052604090205460ff166131105760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610b98565b60a854156131605760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610b98565b613168613aee565b60a65460ff16156131bb5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610b98565b8167ffffffffffffffff16609d54106132165760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a16020526040902054811461327d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610b98565b6132908267ffffffffffffffff1661181f565b6132dc5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156133575760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610b98565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133e75760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610b98565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061345b919061524e565b3410156134aa5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610b98565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b9976346040516135c291815260200190565b60405180910390a35f609d5460016135da91906151ac565b90505b609e548111613632578267ffffffffffffffff168114613620576099545f82815260a260205260408120600101805490919061361a9084906151ac565b90915550505b8061362a816152a6565b9150506135dd565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561366457505f5460ff8083169116105b6136d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610b98565b5f805461ffff191660ff8316176101001781558290036137385760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610b98565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161203b565b335f90815260a56020526040812054908190036138125760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610b98565b335f90815260a5602052604081205561382b82826148e5565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161386691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b0316158015906118475750505f90815260a46020526040902060030154610100900460ff161590565b6138c46139ec565b5f811180156138d557506098548114155b6139215760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610b98565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161203b565b6139676139ec565b6001600160a01b0381166139e35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b98565b61300c8161454c565b6033546001600160a01b031633146122f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b98565b5f805f613a538585614a23565b90505f8160ff165f03613a7457613a6a8686614a93565b9094509050613ae0565b8160ff1660011480613a8957508160ff166002145b15613a9857613a6a8686614afc565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610b98565b808420925050509250929050565b60655460ff16156122f05760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b98565b805f03613b4c575050565b8082035f5b82811015613bf857610100818403811115613b6b57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613bce575f80fd5b505af1158015613be0573d5f803e3d5ffd5b50505050610100830192505061010081019050613b51565b50505050565b6002613c0d6020860186615286565b60ff161115613c5e5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610b98565b6080840135613caf5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610b98565b60a0840135613d005760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610b98565b5f80613d126115c860208801886151ed565b915091505f613d25836001015160c01c90565b90505f60a181613d368460016151ac565b81526020019081526020015f205414613d915760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610b98565b609e548114613de25760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610b98565b5f81815260a160205260409020548214613e3e5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610b98565b5f81815260ab6020526040902054608088013514613e9e5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610b98565b5f613ead846011015160c01c90565b90505f613ed9613ec360608b0160408c016152dd565b613ed360808c0160608d01615265565b84614b4f565b9050613eeb60808a0160608b01615265565b60019384019361ffff91909116929092019160f990613f0d60208c018c615286565b60ff1610613f1a57506101015b604080518281019091529550613f3f86613f3760208d018d615286565b60ff16614b93565b60c084901b6001870152613f6d86613f5d60808d0160608e01615265565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152613fd186613fb260208c018c6151ed565b604051613fc09291906152f6565b604051809103902060b99190910152565b60d986018590526001613fe760208c018c615286565b60ff1610614019576140198661400360608d0160408e016152dd565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff16156140825760a7545f90815260a460205260409020600201546099544291614075916151ac565b61407f91906151bf565b90505b604051806080016040528042815260200182609854426140a291906151ac565b6140ac91906151ac565b81526020016140c160608e0160408f016152dd565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e8690556097546001600160a01b031692506374fe27b791508a359061413b90614135908d018d6151ed565b5f614b9a565b5f61414960408e018e6151ed565b6040518663ffffffff1660e01b815260040161416995949392919061534c565b602060405180830381865afa158015614184573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141a891906151d2565b61421a5760405162461bcd60e51b815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f816002036142ed575f6040515f5b80498061427a5750614289565b6020820283015260010161426d565b6020810280832092016040529092509050806142e75760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610b98565b50919050565b600149156143635760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610b98565b5f4915614371575f49611847565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b806143e65760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610b98565b5f6143f5846001015160c01c90565b90505f614403856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614432876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486144f4885160f81c90565b858888866040518663ffffffff1660e01b81526004016145189594939291906153bf565b5f6040518083038186803b15801561452e575f80fd5b505afa158015614540573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166146315760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614bee565b5f54610100900460ff166146b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f0614c76565b60a88390555f83815260a460205260408082205460975491517f45bc4d1000000000000000000000000000000000000000000000000000000000815260048101869052680100000000000000009091046001600160a01b03908116939216906345bc4d10906024016020604051808303815f875af1158015614741573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614765919061524e565b5f86815260a460205260409020600101549091506147849082906151ac565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906147c39084906151ac565b90915550506040516147d69084906153f0565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061483d908461541c565b6148479190615433565b905061485381836151bf565b60aa5f82825461486391906151ac565b90915550506001600160a01b0384165f90815260a560205260408120805483929061488f9084906151ac565b90915550506040516148a29084906153f0565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b801561498c575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614934576040519150601f19603f3d011682016040523d82523d5f602084013e614939565b606091505b505090508061498a5760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610b98565b505b5050565b614998613aee565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586149cd3390565b6040516001600160a01b03909116815260200160405180910390a1565b6149f2614cfb565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336149cd565b5f81614a715760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610b98565b82825f818110614a8357614a8361546b565b919091013560f81c949350505050565b5f8160f9811015614ae65760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610b98565b6040519150808483378082016040529250929050565b5f816101018114614ae65760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610b98565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614b848161ffff871686614d4d565b82900390912095945050505050565b8082535050565b60605f80808080614bad888a018a615585565b9550955095509550955050818710614bcb579450614be79350505050565b838710614bdf578295505050505050614be7565b509293505050505b9392505050565b5f54610100900460ff16614c6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6065805460ff19169055565b5f54610100900460ff16614cf25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b98565b6122f03361454c565b60655460ff166122f05760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b98565b5f825f03614d5c575082614be7565b609b546001600160a01b03165f5b84811015614e09576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614dd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df4919061524e565b87525060209095019460019384019301614d6a565b5093949350505050565b5f60208284031215614e23575f80fd5b5035919050565b80356001600160a01b0381168114614394575f80fd5b5f60208284031215614e50575f80fd5b614be782614e2a565b5f8083601f840112614e69575f80fd5b50813567ffffffffffffffff811115614e80575f80fd5b602083019150836020828501011115614e97575f80fd5b9250929050565b5f805f60408486031215614eb0575f80fd5b833567ffffffffffffffff811115614ec6575f80fd5b614ed286828701614e59565b909790965060209590950135949350505050565b5f8060208385031215614ef7575f80fd5b823567ffffffffffffffff811115614f0d575f80fd5b614f1985828601614e59565b90969095509350505050565b5f60e082840312156142e7575f80fd5b5f606082840312156142e7575f80fd5b5f8060408385031215614f56575f80fd5b823567ffffffffffffffff80821115614f6d575f80fd5b614f7986838701614f25565b93506020850135915080821115614f8e575f80fd5b50614f9b85828601614f35565b9150509250929050565b5f805f805f8060808789031215614fba575f80fd5b863567ffffffffffffffff80821115614fd1575f80fd5b614fdd8a838b01614f25565b97506020890135915080821115614ff2575f80fd5b614ffe8a838b01614f35565b96506040890135915080821115615013575f80fd5b61501f8a838b01614e59565b90965094506060890135915080821115615037575f80fd5b5061504489828a01614e59565b979a9699509497509295939492505050565b5f805f805f8060c0878903121561506b575f80fd5b61507487614e2a565b955061508260208801614e2a565b945061509060408801614e2a565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f80604085870312156150c4575f80fd5b843567ffffffffffffffff808211156150db575f80fd5b6150e788838901614e59565b909650945060208701359150808211156150ff575f80fd5b5061510c87828801614e59565b95989497509550505050565b801515811461300c575f80fd5b5f60208284031215615135575f80fd5b8135614be781615118565b803567ffffffffffffffff81168114614394575f80fd5b5f8060408385031215615168575f80fd5b61517183615140565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118475761184761517f565b818103818111156118475761184761517f565b5f602082840312156151e2575f80fd5b8151614be781615118565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615220575f80fd5b83018035915067ffffffffffffffff82111561523a575f80fd5b602001915036819003821315614e97575f80fd5b5f6020828403121561525e575f80fd5b5051919050565b5f60208284031215615275575f80fd5b813561ffff81168114614be7575f80fd5b5f60208284031215615296575f80fd5b813560ff81168114614be7575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036152d6576152d661517f565b5060010190565b5f602082840312156152ed575f80fd5b614be782615140565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b818110156153965784516001600160a01b031683529383019391830191600101615371565b505087604086015284810360608601526153b1818789615305565b9a9950505050505050505050565b858152846020820152608060408201525f6153de608083018587615305565b90508260608301529695505050505050565b5f82515f5b8181101561540f57602081860181015185830152016153f5565b505f920191825250919050565b80820281158282048414176118475761184761517f565b5f82615466577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f8301126154d4575f80fd5b8135602067ffffffffffffffff808311156154f1576154f1615498565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561553457615534615498565b6040529384526020818701810194908101925087851115615553575f80fd5b6020870191505b8482101561557a5761556b82614e2a565b8352918301919083019061555a565b979650505050505050565b5f805f805f8060c0878903121561559a575f80fd5b86359550602087013567ffffffffffffffff808211156155b8575f80fd5b6155c48a838b016154c5565b96506040890135955060608901359150808211156155e0575f80fd5b6155ec8a838b016154c5565b94506080890135935060a0890135915080821115615608575f80fd5b5061561589828a016154c5565b915050929550929550929556fea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddr\",\"type\":\"address\"}],\"name\":\"SubmitterContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_submitterContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newSubmitter\",\"type\":\"address\"}],\"name\":\"initialize4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"submitterContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60a060405234801562000010575f80fd5b50604051620055d4380380620055d483398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b6080516154766200015e5f395f81816106a0015261451901526154765ff3fe60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610af6578063f2fde38b14610b15578063f8fa010f14610b34578063fb1e8b0414610b53575f80fd5b8063d8dc99d214610aad578063de8b303514610ac2578063dff7827e14610ae1575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a47578063ce5db8d614610a5a578063cf9a674514610a6f578063d279c19114610a8e575f80fd5b8063b8d0a1b0146109ea578063bedb86fb14610a09578063c555389214610a28575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d314610978578063b34844251461098d578063b35dac4e146109ac578063b3e0a509146109cb575f80fd5b8063a479265d14610919578063a4f209b01461092e578063abc8d68d1461094d575f80fd5b8063910129d411610198578063910129d41461087c57806397fc007c146108ad578063a3c9e94c146108cc578063a415d8dc146108eb575f80fd5b806388b1ea09146107965780638da5cb5b146107af5780638f1d3776146107cc575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa146107195780636c578c1d14610744578063715018a614610763578063728cdbca14610777575f80fd5b80635f77cf1d1461068f57806361267290146106db57806367caa37a146106fa575f80fd5b806341f756da1161026e57806341f756da146105d457806357e0af6c146105e75780635c975abb146106065780635ef7a94a1461061d575f80fd5b80632b7ac3f3146105695780633b70c18a146105a05780633e001b66146105bf575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004614ed4565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004614f01565b610b68565b005b3480156103fb575f80fd5b506103ee61040a366004614f5f565b610c3a565b34801561041a575f80fd5b50610397610429366004614ed4565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004614fa7565b610f76565b348015610470575f80fd5b506103ee61047f366004614ff6565b611493565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004614ed4565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004614ed4565b611852565b3480156104f3575f80fd5b506103c1610502366004614ed4565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004614ed4565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004614ed4565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c54610588906001600160a01b031681565b6040516001600160a01b0390911681526020016103a3565b3480156105ab575f80fd5b50609b54610588906001600160a01b031681565b3480156105ca575f80fd5b506103c160aa5481565b6103ee6105e2366004615084565b611880565b3480156105f2575f80fd5b506103ee610601366004614ed4565b611b84565b348015610611575f80fd5b5060655460ff16610397565b348015610628575f80fd5b50610666610637366004614ed4565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103a3565b34801561069a575f80fd5b506106c27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b3480156106e6575f80fd5b506103ee6106f5366004614ed4565b611c2f565b348015610705575f80fd5b506103ee610714366004615084565b611e0a565b348015610724575f80fd5b506103c1610733366004614ed4565b60ab6020525f908152604090205481565b34801561074f575f80fd5b506103ee61075e366004614f01565b612155565b34801561076e575f80fd5b506103ee612212565b348015610782575f80fd5b506103ee6107913660046150be565b612225565b3480156107a1575f80fd5b5060a6546103979060ff1681565b3480156107ba575f80fd5b506033546001600160a01b0316610588565b3480156107d7575f80fd5b506108386107e6366004614ed4565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b348015610887575f80fd5b50610397610896366004614ed4565b5f90815260a4602052604090206003015460ff1690565b3480156108b8575f80fd5b506103ee6108c7366004614f01565b61252e565b3480156108d7575f80fd5b50609754610588906001600160a01b031681565b3480156108f6575f80fd5b50610397610905366004614f01565b609f6020525f908152604090205460ff1681565b348015610924575f80fd5b506103c160995481565b348015610939575f80fd5b506103ee610948366004614ed4565b612611565b348015610958575f80fd5b506103c1610967366004614f01565b60a56020525f908152604090205481565b348015610983575f80fd5b506103c160a85481565b348015610998575f80fd5b506103ee6109a7366004615119565b6126c1565b3480156109b7575f80fd5b506103ee6109c6366004614f01565b6129ce565b3480156109d6575f80fd5b506103ee6109e5366004614fa7565b612a27565b3480156109f5575f80fd5b506103ee610a04366004615119565b612db8565b348015610a14575f80fd5b506103ee610a2336600461518d565b612e41565b348015610a33575f80fd5b506103ee610a42366004614ed4565b612f7f565b6103ee610a553660046151bf565b613022565b348015610a65575f80fd5b506103c160985481565b348015610a7a575f80fd5b506103ee610a89366004614ed4565b6135b4565b348015610a99575f80fd5b506103ee610aa8366004614f01565b613723565b348015610ab8575f80fd5b506103c160ac5481565b348015610acd575f80fd5b50610397610adc366004614ed4565b6137e2565b348015610aec575f80fd5b506103c1609a5481565b348015610b01575f80fd5b506103ee610b10366004614ed4565b61382c565b348015610b20575f80fd5b506103ee610b2f366004614f01565b6138cf565b348015610b3f575f80fd5b506103ee610b4e366004614f01565b61395c565b348015610b5e575f80fd5b506103c160a95481565b610b70613c0d565b6001600160a01b0381165f908152609f602052604090205460ff1615610bdd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c42613c0d565b5f8111610c915760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bd4565b5f80610c9d8585613c67565b915091505f610cb0836001015160c01c90565b5f81815260a160205260409020549091508214610d0f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f60a181610d1d8785615214565b81526020019081526020015f205414610d9d5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b609d548111610e145760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b610e1f600182615227565b609e555b8315610f6e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e6b816137e2565b15610ec6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610eb6908490615214565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f26575060a85481145b15610f30575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e23575b505050505050565b60a85415610fc65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b610fce613d0f565b5f80610fda8484613c67565b915091505f610fed836001015160c01c90565b5f81815260a16020526040902054909150821461104c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61105581611852565b6110a15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b6110aa816137e2565b156110f75760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a4602052604090206003015460ff16156111585760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bd4565b5f81815260a260205260409020600101544210156111b85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bd4565b605983015160a05f6111cb600185615227565b81526020019081526020015f2054146112265760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f81815260a06020526040902054156112815760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bd4565b80609d54600101146112d55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b609d819055600160a35f6112ea866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561133961132c846011015160c01c90565b600985015160c01c613d62565b60a25f611347600184615227565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113a39084615227565b81526020019081526020015f205f905560ad5f6001836113c39190615227565b81526020019081526020015f205f905560a45f6001836113e39190615227565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61146f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156114e35760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6114eb613d0f565b60ac54609e545f90815260a260205260408120549091429161150d9190615214565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611589919061523a565b6115939190615214565b109050811580156115a15750805b15611608575f6115b76080890160608a01615251565b61ffff16116116085760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b81806116115750805b61165d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bd4565b5f61167361166e60208a018a615272565b613c67565b5090505f611685826001015160c01c90565b611690906001615214565b5f81815260ad60205260408120549192509015611730575f491561171c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bd4565b505f81815260ad602052604090205461174b565b61174861174060208c018c6152d3565b60ff16613e19565b90505b6117568a5f83613f54565b5f806117628b8b613c67565b915091505f611775836001015160c01c90565b905080609e54146117c85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146118245760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f81815260a26020526040902042600190910155611843838b8b6144aa565b50505050505050505050505050565b5f81815260a260205260408120541580159061187a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191091906152f3565b61195c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a854156119ac5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6119b4613d0f565b5f6119c561166e6020840184615272565b5090505f6119d7826001015160c01c90565b6119e2906001615214565b5f81815260ad602052604090205490915015611a665760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aee919061523a565b611af89190615214565b1015611b60575f611b0f6080850160608601615251565b61ffff1611611b605760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b5f611b7161174060208601866152d3565b9050611b7e843383613f54565b50505050565b611b8c613c0d565b5f81118015611b9d57506099548114155b611be95760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bd4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c4f57505f5460ff8083169116105b611cc15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff831617610100179055611cdf5f5460ff1690565b60ff16600214611d315760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bd4565b81611da45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bd4565b609e545f90815260ab6020526040902054611dcd57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e9a91906152f3565b611ee65760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a85415611f365760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b611f3e613d0f565b5f4915611f8d5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bd4565b5f611f9e61166e6020840184615272565b5090505f611fb0826001015160c01c90565b611fbb906001615214565b5f81815260ad602052604090205490915061203e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120c6919061523a565b6120d09190615214565b1015612138575f6120e76080850160608601615251565b61ffff16116121385760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b61215083335f84815260ad6020526040902054613f54565b505050565b61215d613c0d565b6001600160a01b0381165f908152609f602052604090205460ff166121c45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bd4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c2f565b61221a613c0d565b6122235f61465d565b565b5f54610100900460ff161580801561224357505f54600160ff909116105b8061225c5750303b15801561225c57505f5460ff166001145b6122ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805460ff1916600117905580156122ef575f805461ff0019166101001790555b6001600160a01b038616158061230c57506001600160a01b038516155b15612343576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123995760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bd4565b6123a16146c6565b6123a961474a565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612525575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612536613c0d565b6001600160a01b0381161580159061255c5750609c546001600160a01b03828116911614155b6125a85760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bd4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612619613c0d565b5f81118015612629575060648111155b8015612637575060a9548114155b6126835760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bd4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c23565b60a854156127115760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b612719613d0f565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612785573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127a991906152f3565b6127f55760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b5f806128018686613c67565b915091505f612814836001015160c01c90565b5f81815260a1602052604090205490915082146128735760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61287c816137e2565b6128c85760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff19169055609954600290910154429161290491615214565b11612983575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f7574000000000000000000000000000000000000000000000000009183019190915261297e9183916001600160a01b0316906147ce565b612525565b61298e8386866144aa565b61252581336040518060400160405280600d81526020017f50726f6f6620737563636573730000000000000000000000000000000000000081525061492d565b6129d6613c0d565b60aa80545f9091556129e882826149f9565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c23565b612a2f613c0d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612aa65760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bd4565b5f80612ab28484613c67565b915091505f612ac5836001015160c01c90565b90508015612b155760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bd4565b5f612b21846079015190565b905080612b705760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bd4565b600984015160c01c15612bc55760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bd4565b5f612bd1856019015190565b03612c1e5760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bd4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c4a856039015190565b14612c975760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bd4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612dc48686613c67565b915091505f612dd7836001015160c01c90565b5f81815260a160205260409020549091508214612e365760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6125258386866144aa565b612e49613c0d565b8015612f4d57612e57614aa2565b60a65460ff1615612f0c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612eab908490615214565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f55614afc565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f2f565b50565b612f87613c0d565b5f81118015612f98575060ac548114155b612fe45760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bd4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c23565b335f908152609f602052604090205460ff166130805760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bd4565b60a854156130d05760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6130d8613d0f565b60a65460ff161561312b5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bd4565b8167ffffffffffffffff16609d54106131865760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a1602052604090205481146131ed5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6132008267ffffffffffffffff16611852565b61324c5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132c75760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133575760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bd4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133cb919061523a565b34101561341a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161353291815260200190565b60405180910390a35f609d54600161354a9190615214565b90505b609e5481116135a2578267ffffffffffffffff168114613590576099545f82815260a260205260408120600101805490919061358a908490615214565b90915550505b8061359a8161530e565b91505061354d565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135d457505f5460ff8083169116105b6136465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001781558290036136a85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bd4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b335f90815260a56020526040812054908190036137825760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bd4565b335f90815260a5602052604081205561379b82826149f9565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137d691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061187a5750505f90815260a46020526040902060030154610100900460ff161590565b613834613c0d565b5f8111801561384557506098548114155b6138915760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bd4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c23565b6138d7613c0d565b6001600160a01b0381166139535760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bd4565b612f7c8161465d565b5f54600490610100900460ff1615801561397c57505f5460ff8083169116105b6139ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001790556001600160a01b03821615801590613a2257505f826001600160a01b03163b115b613a6e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bd4565b609d54609e5414613ac15760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610bd4565b60a65460ff1615613b145760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bd4565b60a85415613b645760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6097546040516001600160a01b038085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6033546001600160a01b031633146122235760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bd4565b5f805f613c748585614b35565b90505f8160ff165f03613c9557613c8b8686614ba5565b9094509050613d01565b8160ff1660011480613caa57508160ff166002145b15613cb957613c8b8686614c0e565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bd4565b808420925050509250929050565b60655460ff16156122235760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bd4565b805f03613d6d575050565b8082035f5b82811015611b7e57610100818403811115613d8c57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613def575f80fd5b505af1158015613e01573d5f803e3d5ffd5b50505050610100830192505061010081019050613d72565b5f81600203613ea8575f6040515f5b804980613e355750613e44565b60208202830152600101613e28565b602081028083209201604052909250905080613ea25760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bd4565b50919050565b60014915613f1e5760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bd4565b5f4915613f2c575f4961187a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002613f6360208501856152d3565b60ff161115613fb45760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bd4565b60808301356140055760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bd4565b60a08301356140565760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bd4565b5f8061406861166e6020870187615272565b915091505f61407b836001015160c01c90565b90505f60a18161408c846001615214565b81526020019081526020015f2054146140e75760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bd4565b609e5481146141385760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146141945760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bd4565b5f81815260ab60205260409020546080870135146141f45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f614203846011015160c01c90565b90505f61422f61421960608a0160408b01615345565b61422960808b0160608c01615251565b84614c61565b90506142416080890160608a01615251565b60019384019361ffff91909116929092019160f99061426360208b018b6152d3565b60ff161061427057506101015b6040805182810190915295506142958661428d60208c018c6152d3565b60ff16614ca5565b60c084901b60018701526142c3866142b360808c0160608d01615251565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161431360208b018b6152d3565b60ff1610614345576143458661432f60608c0160408d01615345565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156143ae5760a7545f90815260a4602052604090206002015460995442916143a191615214565b6143ab9190615227565b90505b604051806080016040528042815260200182609854426143ce9190615214565b6143d89190615214565b81526020016143ed60608d0160408e01615345565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806144f75760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bd4565b5f614506846001015160c01c90565b90505f614514856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614543876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a848614605885160f81c90565b858888866040518663ffffffff1660e01b815260040161462995949392919061535e565b5f6040518083038186803b15801561463f575f80fd5b505afa158015614651573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147425760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614cac565b5f54610100900460ff166147c65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614d34565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614855573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614879919061523a565b5f86815260a46020526040902060010154909150614898908290615214565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906148d7908490615214565b90915550506040516148ea9084906153c1565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061495190846153ed565b61495b9190615404565b90506149678183615227565b60aa5f8282546149779190615214565b90915550506001600160a01b0384165f90815260a56020526040812080548392906149a3908490615214565b90915550506040516149b69084906153c1565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614a9e575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a48576040519150601f19603f3d011682016040523d82523d5f602084013e614a4d565b606091505b50509050806121505760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bd4565b5050565b614aaa613d0f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614adf3390565b6040516001600160a01b03909116815260200160405180910390a1565b614b04614db9565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614adf565b5f81614b835760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bd4565b82825f818110614b9557614b9561543c565b919091013560f81c949350505050565b5f8160f9811015614bf85760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bd4565b6040519150808483378082016040529250929050565b5f816101018114614bf85760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bd4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614c968161ffff871686614e0b565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614d285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6065805460ff19169055565b5f54610100900460ff16614db05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6122233361465d565b60655460ff166122235760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bd4565b5f825f03614e1a575082614ecd565b609b546001600160a01b03165f5b84811015614ec7576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614e8e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614eb2919061523a565b87525060209095019460019384019301614e28565b50849150505b9392505050565b5f60208284031215614ee4575f80fd5b5035919050565b80356001600160a01b0381168114613f4f575f80fd5b5f60208284031215614f11575f80fd5b614ecd82614eeb565b5f8083601f840112614f2a575f80fd5b50813567ffffffffffffffff811115614f41575f80fd5b602083019150836020828501011115614f58575f80fd5b9250929050565b5f805f60408486031215614f71575f80fd5b833567ffffffffffffffff811115614f87575f80fd5b614f9386828701614f1a565b909790965060209590950135949350505050565b5f8060208385031215614fb8575f80fd5b823567ffffffffffffffff811115614fce575f80fd5b614fda85828601614f1a565b90969095509350505050565b5f60e08284031215613ea2575f80fd5b5f805f805f6060868803121561500a575f80fd5b853567ffffffffffffffff80821115615021575f80fd5b61502d89838a01614fe6565b96506020880135915080821115615042575f80fd5b61504e89838a01614f1a565b90965094506040880135915080821115615066575f80fd5b5061507388828901614f1a565b969995985093965092949392505050565b5f60208284031215615094575f80fd5b813567ffffffffffffffff8111156150aa575f80fd5b6150b684828501614fe6565b949350505050565b5f805f805f8060c087890312156150d3575f80fd5b6150dc87614eeb565b95506150ea60208801614eeb565b94506150f860408801614eeb565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561512c575f80fd5b843567ffffffffffffffff80821115615143575f80fd5b61514f88838901614f1a565b90965094506020870135915080821115615167575f80fd5b5061517487828801614f1a565b95989497509550505050565b8015158114612f7c575f80fd5b5f6020828403121561519d575f80fd5b8135614ecd81615180565b803567ffffffffffffffff81168114613f4f575f80fd5b5f80604083850312156151d0575f80fd5b6151d9836151a8565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561187a5761187a6151e7565b8181038181111561187a5761187a6151e7565b5f6020828403121561524a575f80fd5b5051919050565b5f60208284031215615261575f80fd5b813561ffff81168114614ecd575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152a5575f80fd5b83018035915067ffffffffffffffff8211156152bf575f80fd5b602001915036819003821315614f58575f80fd5b5f602082840312156152e3575f80fd5b813560ff81168114614ecd575f80fd5b5f60208284031215615303575f80fd5b8151614ecd81615180565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361533e5761533e6151e7565b5060010190565b5f60208284031215615355575f80fd5b614ecd826151a8565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156153e057602081860181015185830152016153c6565b505f920191825250919050565b808202811582820484141761187a5761187a6151e7565b5f82615437577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a", } // RollupABI is the input ABI used to generate the binding from. @@ -408,21 +401,21 @@ func (_Rollup *RollupCallerSession) BatchChallengedSuccess(batchIndex *big.Int) // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { var out []interface{} err := _Rollup.contract.Call(opts, &out, "batchDataStore", batchIndex) outstruct := new(struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }) if err != nil { return *outstruct, err @@ -431,7 +424,7 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big outstruct.OriginTimestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.FinalizeTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) outstruct.BlockNumber = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.SignedSequencersBitmap = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Submitter = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) return *outstruct, err @@ -439,24 +432,24 @@ func (_Rollup *RollupCaller) BatchDataStore(opts *bind.CallOpts, batchIndex *big // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } // BatchDataStore is a free data retrieval call binding the contract method 0x5ef7a94a. // -// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, uint256 signedSequencersBitmap) +// Solidity: function batchDataStore(uint256 batchIndex) view returns(uint256 originTimestamp, uint256 finalizeTimestamp, uint256 blockNumber, address submitter) func (_Rollup *RollupCallerSession) BatchDataStore(batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return _Rollup.Contract.BatchDataStore(&_Rollup.CallOpts, batchIndex) } @@ -836,37 +829,6 @@ func (_Rollup *RollupCallerSession) IsChallenger(challengerAddress common.Addres return _Rollup.Contract.IsChallenger(&_Rollup.CallOpts, challengerAddress) } -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupCaller) L1StakingContract(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _Rollup.contract.Call(opts, &out, "l1StakingContract") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupSession) L1StakingContract() (common.Address, error) { - return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) -} - -// L1StakingContract is a free data retrieval call binding the contract method 0xddd8a3dc. -// -// Solidity: function l1StakingContract() view returns(address) -func (_Rollup *RollupCallerSession) L1StakingContract() (common.Address, error) { - return _Rollup.Contract.L1StakingContract(&_Rollup.CallOpts) -} - // LastCommittedBatchIndex is a free data retrieval call binding the contract method 0x121dcd50. // // Solidity: function lastCommittedBatchIndex() view returns(uint256) @@ -1206,6 +1168,37 @@ func (_Rollup *RollupCallerSession) RollupDelayPeriod() (*big.Int, error) { return _Rollup.Contract.RollupDelayPeriod(&_Rollup.CallOpts) } +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupCaller) SubmitterContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Rollup.contract.Call(opts, &out, "submitterContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupSession) SubmitterContract() (common.Address, error) { + return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) +} + +// SubmitterContract is a free data retrieval call binding the contract method 0xa3c9e94c. +// +// Solidity: function submitterContract() view returns(address) +func (_Rollup *RollupCallerSession) SubmitterContract() (common.Address, error) { + return _Rollup.Contract.SubmitterContract(&_Rollup.CallOpts) +} + // Verifier is a free data retrieval call binding the contract method 0x2b7ac3f3. // // Solidity: function verifier() view returns(address) @@ -1352,67 +1345,67 @@ func (_Rollup *RollupTransactorSession) ClaimReward(receiver common.Address) (*t return _Rollup.Contract.ClaimReward(&_Rollup.TransactOpts, receiver) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupTransactor) CommitBatch(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatch", batchDataInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) } -// CommitBatch is a paid mutator transaction binding the contract method 0x428868b5. +// CommitBatch is a paid mutator transaction binding the contract method 0x41f756da. // -// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) payable returns() -func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitBatch((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) payable returns() +func (_Rollup *RollupTransactorSession) CommitBatch(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatch(&_Rollup.TransactOpts, batchDataInput) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactor) CommitBatchWithProof(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitBatchWithProof", batchDataInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) } -// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x4e8f1d67. +// CommitBatchWithProof is a paid mutator transaction binding the contract method 0x1544ba3a. // -// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput, bytes _batchHeader, bytes _batchProof) returns() -func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { - return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput, _batchHeader, _batchProof) +// Solidity: function commitBatchWithProof((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, bytes _batchHeader, bytes _batchProof) returns() +func (_Rollup *RollupTransactorSession) CommitBatchWithProof(batchDataInput IRollupBatchDataInput, _batchHeader []byte, _batchProof []byte) (*types.Transaction, error) { + return _Rollup.Contract.CommitBatchWithProof(&_Rollup.TransactOpts, batchDataInput, _batchHeader, _batchProof) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "commitState", batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupTransactor) CommitState(opts *bind.TransactOpts, batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "commitState", batchDataInput) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) } -// CommitState is a paid mutator transaction binding the contract method 0x1e8825be. +// CommitState is a paid mutator transaction binding the contract method 0x67caa37a. // -// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput, (uint256,bytes,bytes) batchSignatureInput) returns() -func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput, batchSignatureInput IRollupBatchSignatureInput) (*types.Transaction, error) { - return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput, batchSignatureInput) +// Solidity: function commitState((uint8,bytes,uint64,uint16,bytes32,bytes32,bytes32) batchDataInput) returns() +func (_Rollup *RollupTransactorSession) CommitState(batchDataInput IRollupBatchDataInput) (*types.Transaction, error) { + return _Rollup.Contract.CommitState(&_Rollup.TransactOpts, batchDataInput) } // FinalizeBatch is a paid mutator transaction binding the contract method 0x13361101. @@ -1459,23 +1452,23 @@ func (_Rollup *RollupTransactorSession) ImportGenesisBatch(_batchHeader []byte) // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "initialize", _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactor) Initialize(opts *bind.TransactOpts, _submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize", _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize is a paid mutator transaction binding the contract method 0x728cdbca. // -// Solidity: function initialize(address _l1StakingContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() -func (_Rollup *RollupTransactorSession) Initialize(_l1StakingContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { - return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _l1StakingContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) +// Solidity: function initialize(address _submitterContract, address _messageQueue, address _verifier, uint256 _finalizationPeriodSeconds, uint256 _proofWindow, uint256 _proofRewardPercent) returns() +func (_Rollup *RollupTransactorSession) Initialize(_submitterContract common.Address, _messageQueue common.Address, _verifier common.Address, _finalizationPeriodSeconds *big.Int, _proofWindow *big.Int, _proofRewardPercent *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize(&_Rollup.TransactOpts, _submitterContract, _messageQueue, _verifier, _finalizationPeriodSeconds, _proofWindow, _proofRewardPercent) } // Initialize2 is a paid mutator transaction binding the contract method 0x61267290. @@ -1520,6 +1513,27 @@ func (_Rollup *RollupTransactorSession) Initialize3(_rollupDelayPeriod *big.Int) return _Rollup.Contract.Initialize3(&_Rollup.TransactOpts, _rollupDelayPeriod) } +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupTransactor) Initialize4(opts *bind.TransactOpts, _newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize4", _newSubmitter) +} + +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +} + +// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// +// Solidity: function initialize4(address _newSubmitter) returns() +func (_Rollup *RollupTransactorSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +} + // ProveState is a paid mutator transaction binding the contract method 0xb3484425. // // Solidity: function proveState(bytes _batchHeader, bytes _batchProof) returns() @@ -3250,6 +3264,159 @@ func (_Rollup *RollupFilterer) ParseRevertBatch(log types.Log) (*RollupRevertBat return event, nil } +// RollupSubmitterContractUpdatedIterator is returned from FilterSubmitterContractUpdated and is used to iterate over the raw logs and unpacked data for SubmitterContractUpdated events raised by the Rollup contract. +type RollupSubmitterContractUpdatedIterator struct { + Event *RollupSubmitterContractUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *RollupSubmitterContractUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(RollupSubmitterContractUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(RollupSubmitterContractUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *RollupSubmitterContractUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *RollupSubmitterContractUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// RollupSubmitterContractUpdated represents a SubmitterContractUpdated event raised by the Rollup contract. +type RollupSubmitterContractUpdated struct { + OldAddr common.Address + NewAddr common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterContractUpdated is a free log retrieval operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterOpts, oldAddr []common.Address, newAddr []common.Address) (*RollupSubmitterContractUpdatedIterator, error) { + + var oldAddrRule []interface{} + for _, oldAddrItem := range oldAddr { + oldAddrRule = append(oldAddrRule, oldAddrItem) + } + var newAddrRule []interface{} + for _, newAddrItem := range newAddr { + newAddrRule = append(newAddrRule, newAddrItem) + } + + logs, sub, err := _Rollup.contract.FilterLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + if err != nil { + return nil, err + } + return &RollupSubmitterContractUpdatedIterator{contract: _Rollup.contract, event: "SubmitterContractUpdated", logs: logs, sub: sub}, nil +} + +// WatchSubmitterContractUpdated is a free log subscription operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpts, sink chan<- *RollupSubmitterContractUpdated, oldAddr []common.Address, newAddr []common.Address) (event.Subscription, error) { + + var oldAddrRule []interface{} + for _, oldAddrItem := range oldAddr { + oldAddrRule = append(oldAddrRule, oldAddrItem) + } + var newAddrRule []interface{} + for _, newAddrItem := range newAddr { + newAddrRule = append(newAddrRule, newAddrItem) + } + + logs, sub, err := _Rollup.contract.WatchLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(RollupSubmitterContractUpdated) + if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterContractUpdated is a log parse operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +func (_Rollup *RollupFilterer) ParseSubmitterContractUpdated(log types.Log) (*RollupSubmitterContractUpdated, error) { + event := new(RollupSubmitterContractUpdated) + if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // RollupUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the Rollup contract. type RollupUnpausedIterator struct { Event *RollupUnpaused // Event containing the contract specifics and raw log diff --git a/bindings/bindings/rollup_more.go b/bindings/bindings/rollup_more.go index a78f509fd..46a077421 100644 --- a/bindings/bindings/rollup_more.go +++ b/bindings/bindings/rollup_more.go @@ -9,11 +9,11 @@ import ( "morph-l2/bindings/solc" ) -const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"l1StakingContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1030_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1032_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1033_storage\"},\"t_struct(BatchChallenge)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" +const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"submitterContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1030_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1032_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1033_storage\"},\"t_struct(BatchChallenge)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" var RollupStorageLayout = new(solc.StorageLayout) -var RollupDeployedBin = "0x608060405260043610610353575f3560e01c8063728cdbca116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063dff7827e1161006d578063dff7827e14610b1f578063e3fff1dd14610b34578063f2fde38b14610b53578063fb1e8b0414610b72575f80fd5b8063d8dc99d214610abf578063ddd8a3dc14610ad4578063de8b303514610b00575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a59578063ce5db8d614610a6c578063cf9a674514610a81578063d279c19114610aa0575f80fd5b8063b8d0a1b0146109fc578063bedb86fb14610a1b578063c555389214610a3a575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d31461098a578063b34844251461099f578063b35dac4e146109be578063b3e0a509146109dd575f80fd5b8063a479265d1461092b578063a4f209b014610940578063abc8d68d1461095f575f80fd5b80638f1d3776116101985780638f1d3776146107e3578063910129d4146108ad57806397fc007c146108de578063a415d8dc146108fd575f80fd5b8063728cdbca1461078157806388b1ea09146107a05780638da5cb5b146107b9575f80fd5b80632a213ba1116102935780635c975abb11610233578063612672901161020e578063612672901461070457806368589dfa146107235780636c578c1d1461074e578063715018a61461076d575f80fd5b80635c975abb146106415780635ef7a94a146106585780635f77cf1d146106b8575f80fd5b80633e001b661161026e5780633e001b66146105db578063428868b5146105f05780634e8f1d671461060357806357e0af6c14610622575f80fd5b80632a213ba1146105335780632b7ac3f31461055e5780633b70c18a146105af575f80fd5b806313361101116102fe5780631e8825be116102d95780631e8825be1461049f57806321e2f9e0146104be5780632362f03e146104dd5780632571098d14610508575f80fd5b8063133611011461043b57806318463fb01461045a57806318af3b2b1461046f575f80fd5b806310d445831161032e57806310d44583146103e5578063116a1f4214610404578063121dcd5014610426575f80fd5b806304d772151461035e578063059def61146103a15780630ceb6780146103c4575f80fd5b3661035a57005b5f80fd5b348015610369575f80fd5b5061038c610378366004615c9f565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103ac575f80fd5b506103b6609d5481565b604051908152602001610398565b3480156103cf575f80fd5b506103e36103de366004615cd9565b610b87565b005b3480156103f0575f80fd5b506103e36103ff366004615d37565b610cab565b34801561040f575f80fd5b5061038c61041e366004615c9f565b609d54101590565b348015610431575f80fd5b506103b6609e5481565b348015610446575f80fd5b506103e3610455366004615d7f565b611097565b348015610465575f80fd5b506103b660a75481565b34801561047a575f80fd5b5061038c610489366004615c9f565b5f90815260a26020526040902060010154421090565b3480156104aa575f80fd5b506103e36104b9366004615dde565b6116b6565b3480156104c9575f80fd5b5061038c6104d8366004615c9f565b611b64565b3480156104e8575f80fd5b506103b66104f7366004615c9f565b60a16020525f908152604090205481565b348015610513575f80fd5b506103b6610522366004615c9f565b60a06020525f908152604090205481565b34801561053e575f80fd5b506103b661054d366004615c9f565b60ad6020525f908152604090205481565b348015610569575f80fd5b50609c5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610398565b3480156105ba575f80fd5b50609b5461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105e6575f80fd5b506103b660aa5481565b6103e36105fe366004615dde565b611b92565b34801561060e575f80fd5b506103e361061d366004615e3e565b611fd6565b34801561062d575f80fd5b506103e361063c366004615c9f565b612440565b34801561064c575f80fd5b5060655460ff1661038c565b348015610663575f80fd5b50610698610672366004615c9f565b60a26020525f908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610398565b3480156106c3575f80fd5b506106eb7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610398565b34801561070f575f80fd5b506103e361071e366004615c9f565b612505565b34801561072e575f80fd5b506103b661073d366004615c9f565b60ab6020525f908152604090205481565b348015610759575f80fd5b506103e3610768366004615cd9565b612768565b348015610778575f80fd5b506103e3612877565b34801561078c575f80fd5b506103e361079b366004615eef565b61288a565b3480156107ab575f80fd5b5060a65461038c9060ff1681565b3480156107c4575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff1661058a565b3480156107ee575f80fd5b5061085c6107fd366004615c9f565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c001610398565b3480156108b8575f80fd5b5061038c6108c7366004615c9f565b5f90815260a4602052604090206003015460ff1690565b3480156108e9575f80fd5b506103e36108f8366004615cd9565b612c53565b348015610908575f80fd5b5061038c610917366004615cd9565b609f6020525f908152604090205460ff1681565b348015610936575f80fd5b506103b660995481565b34801561094b575f80fd5b506103e361095a366004615c9f565b612d77565b34801561096a575f80fd5b506103b6610979366004615cd9565b60a56020525f908152604090205481565b348015610995575f80fd5b506103b660a85481565b3480156109aa575f80fd5b506103e36109b9366004615f4a565b612e41565b3480156109c9575f80fd5b506103e36109d8366004615cd9565b613220565b3480156109e8575f80fd5b506103e36109f7366004615d7f565b613286565b348015610a07575f80fd5b506103e3610a16366004615f4a565b61367f565b348015610a26575f80fd5b506103e3610a35366004615fbe565b613722565b348015610a45575f80fd5b506103e3610a54366004615c9f565b6138b5565b6103e3610a67366004615ff0565b613972565b348015610a77575f80fd5b506103b660985481565b348015610a8c575f80fd5b506103e3610a9b366004615c9f565b614087565b348015610aab575f80fd5b506103e3610aba366004615cd9565b614264565b348015610aca575f80fd5b506103b660ac5481565b348015610adf575f80fd5b5060975461058a9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610b0b575f80fd5b5061038c610b1a366004615c9f565b61434a565b348015610b2a575f80fd5b506103b6609a5481565b348015610b3f575f80fd5b506103e3610b4e366004615c9f565b6143a1565b348015610b5e575f80fd5b506103e3610b6d366004615cd9565b61445e565b348015610b7d575f80fd5b506103b660a95481565b610b8f614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610c23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610cb3614512565b5f8111610d1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c1a565b5f80610d288585614593565b915091505f610d3b836001015160c01c90565b5f81815260a160205260409020549091508214610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f60a181610dc28785616045565b81526020019081526020015f205414610e5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b609d548111610eed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b610ef8600182616058565b609e555b831561108f57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610f448161434a565b15610fca575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091610f9c908490616045565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a85415801590611047575060a85481145b15611051575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610efc575b505050505050565b60a85415611101576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611109614655565b5f806111158484614593565b915091505f611128836001015160c01c90565b5f81815260a1602052604090205490915082146111a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6111aa81611b64565b611210576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b6112198161434a565b15611280576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003015460ff16156112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c1a565b5f81815260a26020526040902060010154421015611375576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c1a565b605983015160a05f611388600185616058565b81526020019081526020015f2054146113fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f81815260a0602052604090205415611472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c1a565b80609d54600101146114e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b609d819055600160a35f6114f5866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a06020526040902055611562611555846011015160c01c90565b600985015160c01c6146c2565b60a25f611570600184616058565b815260208101919091526040015f908120818155600180820183905560028201839055600390910182905560ab91906115a99084616058565b81526020019081526020015f205f905560ad5f6001836115c99190616058565b81526020019081526020015f205f905560a45f6001836115e99190616058565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d611692866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa15801561173c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611760919061606b565b6117c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611838614655565b5f49156118a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c1a565b5f6118b76118b26020850185616086565b614593565b5090505f6118c9826001015160c01c90565b6118d4906001616045565b5f81815260ad6020526040902054909150611971576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa1580156119e2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a0691906160e7565b611a109190616045565b1015611a92575f611a2760808601606087016160fe565b61ffff1611611a92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b3e91906160e7565b9050611b5d85858360ad5f8781526020019081526020015f205461478c565b5050505050565b5f81815260a2602052604081205415801590611b8c57505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611c18573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c3c919061606b565b611ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b60a85415611d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b611d14614655565b5f611d256118b26020850185616086565b5090505f611d37826001015160c01c90565b611d42906001616045565b5f81815260ad602052604090205490915015611de0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610c1a565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e7591906160e7565b611e7f9190616045565b1015611f01575f611e9660808601606087016160fe565b61ffff1611611f01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b6097545f9073ffffffffffffffffffffffffffffffffffffffff1663d096c3c6336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611f89573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fad91906160e7565b90505f611fc8611fc0602088018861611f565b60ff16614ec9565b905061108f8686848461478c565b60a85415612040576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612048614655565b60ac54609e545f90815260a260205260408120549091429161206a9190616045565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120dc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210091906160e7565b61210a9190616045565b109050811580156121185750805b15612199575f61212e60808a0160608b016160fe565b61ffff1611612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c1a565b81806121a25750805b612208576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c1a565b5f6122196118b260208b018b616086565b5090505f61222b826001015160c01c90565b612236906001616045565b5f81815260ad602052604081205491925090156122f0575f49156122dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c1a565b505f81815260ad6020526040902054612303565b612300611fc060208d018d61611f565b90505b61230f8b8b5f8461478c565b5f8061231b8b8b614593565b915091505f61232e836001015160c01c90565b905080609e541461239b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214612411576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b5f81815260a26020526040902042600190910155612430838b8b615038565b5050505050505050505050505050565b612448614512565b5f8111801561245957506099548114155b6124bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c1a565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561252557505f5460ff8083169116105b6125b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556125ec5f5460ff1690565b60ff16600214612658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c1a565b816126e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c1a565b609e545f90815260ab602052604090205461270e57609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b612770614512565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff166127fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c1a565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610ca0565b61287f614512565b6128885f615212565b565b5f54610100900460ff16158080156128a857505f54600160ff909116105b806128c15750303b1580156128c157505f5460ff166001145b61294d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156129a9575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806129e0575073ffffffffffffffffffffffffffffffffffffffff8516155b15612a17576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8716612a94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206c31207374616b696e6720636f6e747261637400000000006044820152606401610c1a565b612a9c615288565b612aa4615326565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612c4a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612c5b614512565b73ffffffffffffffffffffffffffffffffffffffff811615801590612c9b5750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612d01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c1a565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612d7f614512565b5f81118015612d8f575060648111155b8015612d9d575060a9548114155b612e03576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c1a565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b022391016124f9565b60a85415612eab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b612eb3614655565b60975473ffffffffffffffffffffffffffffffffffffffff166368015791336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612f39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5d919061606b565b612fc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920616374697665207374616b657220616c6c6f7765640000000000006044820152606401610c1a565b5f80612fcf8686614593565b915091505f612fe2836001015160c01c90565b5f81815260a16020526040902054909150821461305b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b6130648161434a565b6130ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c1a565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161314191616045565b116131d5575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526131d0918391906153c4565b612c4a565b6131e0838686615038565b612c4a81336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615547565b613228614512565b60aa80545f90915561323a828261562d565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d8791016124f9565b61328e614512565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea541561331f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c1a565b5f8061332b8484614593565b915091505f61333e836001015160c01c90565b905080156133a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c1a565b5f6133b4846079015190565b90508061341d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c1a565b600984015160c01c1561348c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c1a565b5f613498856019015190565b036134ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c1a565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461352b856039015190565b14613592576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c1a565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910155603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061368b8686614593565b915091505f61369e836001015160c01c90565b5f81815260a160205260409020549091508214613717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b612c4a838686615038565b61372a614512565b8015613883576137386156ff565b60a65460ff16156138355760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091613799908490616045565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b61388b615784565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613858565b50565b6138bd614512565b5f811180156138ce575060ac548114155b613934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c1a565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad191016124f9565b335f908152609f602052604090205460ff166139ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c1a565b60a85415613a54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c1a565b613a5c614655565b60a65460ff1615613ac9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c1a565b8167ffffffffffffffff16609d5410613b3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a160205260409020548114613bbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c1a565b613bd28267ffffffffffffffff16611b64565b613c38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613cda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c1a565b67ffffffffffffffff82165f90815260a260205260409020600101544210613d84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c1a565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dee573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1291906160e7565b341015613e7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c1a565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613fe791815260200190565b60405180910390a35f609d546001613fff9190616045565b90505b609e548111614057578267ffffffffffffffff168114614045576099545f82815260a260205260408120600101805490919061403f908490616045565b90915550505b8061404f8161613f565b915050614002565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff161580156140a757505f5460ff8083169116105b614133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c1a565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001781558290036141cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c1a565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016124f9565b335f90815260a56020526040812054908190036142dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c1a565b335f90815260a560205260408120556142f6828261562d565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a8260405161433e91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611b8c5750505f90815260a46020526040902060030154610100900460ff161590565b6143a9614512565b5f811180156143ba57506098548114155b614420576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c1a565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a43791016124f9565b614466614512565b73ffffffffffffffffffffffffffffffffffffffff8116614509576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c1a565b6138b281615212565b60335473ffffffffffffffffffffffffffffffffffffffff163314612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c1a565b5f805f6145a085856157db565b90505f8160ff165f036145c1576145b78686615865565b9094509050614647565b8160ff16600114806145d657508160ff166002145b156145e5576145b786866158e8565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c1a565b808420925050509250929050565b60655460ff1615612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c1a565b805f036146cd575050565b8082035f5b82811015614786576101008184038111156146ec57508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b15801561475c575f80fd5b505af115801561476e573d5f803e3d5ffd5b505050506101008301925050610100810190506146d2565b50505050565b600261479b602086018661611f565b60ff161115614806576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c1a565b6080840135614871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c1a565b60a08401356148dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c1a565b5f806148ee6118b26020880188616086565b915091505f614901836001015160c01c90565b90505f60a181614912846001616045565b81526020019081526020015f205414614987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c1a565b609e5481146149f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c1a565b5f81815260a160205260409020548214614a68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c1a565b5f81815260ab6020526040902054608088013514614ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c1a565b5f614af1846011015160c01c90565b90505f614b1d614b0760608b0160408c01616176565b614b1760808c0160608d016160fe565b84615955565b9050614b2f60808a0160608b016160fe565b60019384019361ffff91909116929092019160f990614b5160208c018c61611f565b60ff1610614b5e57506101015b604080518281019091529550614b8386614b7b60208d018d61611f565b60ff16615999565b60c084901b6001870152614bb186614ba160808d0160608e016160fe565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808b0135605988015260a08b013560798801528a01356099870152614c1586614bf660208c018c616086565b604051614c0492919061618f565b604051809103902060b99190910152565b60d986018590526001614c2b60208c018c61611f565b60ff1610614c5d57614c5d86614c4760608d0160408e01616176565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08e0135905560ad905290812088905560a65460ff1615614cc65760a7545f90815260a460205260409020600201546099544291614cb991616045565b614cc39190616058565b90505b60405180608001604052804281526020018260985442614ce69190616045565b614cf09190616045565b8152602001614d0560608e0160408f01616176565b67ffffffffffffffff16815260209081018b90525f87815260a2825260409081902083518155838301516001820155908301516002820155606090920151600390920191909155609e86905560975473ffffffffffffffffffffffffffffffffffffffff1692506374fe27b791508a3590614d8c90614d86908d018d616086565b5f6159a0565b5f614d9a60408e018e616086565b6040518663ffffffff1660e01b8152600401614dba9594939291906161e5565b602060405180830381865afa158015614dd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614df9919061606b565b614e85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f746865207369676e617475726520766572696669636174696f6e206661696c6560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f83815260a16020526040808220549051909185917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3505050505050505050565b5f81600203614f72575f6040515f5b804980614ee55750614ef4565b60208202830152600101614ed8565b602081028083209201604052909250905080614f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c1a565b50919050565b60014915615002576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c1a565b5f4915615010575f49611b8c565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b8061509f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c1a565b5f6150ae846001015160c01c90565b90505f6150bc856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006150eb876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a8486151ba885160f81c90565b858888866040518663ffffffff1660e01b81526004016151de959493929190616265565b5f6040518083038186803b1580156151f4575f80fd5b505afa158015615206573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff1661531e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b6128886159f4565b5f54610100900460ff166153bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b612888615ab4565b60a88390555f83815260a460205260408082205460975491517f45bc4d10000000000000000000000000000000000000000000000000000000008152600481018690526801000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116939216906345bc4d10906024016020604051808303815f875af1158015615455573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061547991906160e7565b5f86815260a46020526040902060010154909150615498908290616045565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a5909152812080549091906154e4908490616045565b90915550506040516154f7908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061556b90846162c2565b61557591906162d9565b90506155818183616058565b60aa5f8282546155919190616045565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a56020526040812080548392906155ca908490616045565b90915550506040516155dd908490616296565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b80156156fb575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615689576040519150601f19603f3d011682016040523d82523d5f602084013e61568e565b606091505b50509050806156f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c1a565b505b5050565b615707614655565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861575a3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b61578c615b53565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361575a565b5f81615843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c1a565b82825f81811061585557615855616311565b919091013560f81c949350505050565b5f8160f98110156158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c1a565b6040519150808483378082016040529250929050565b5f8161010181146158d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c1a565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f91810161598a8161ffff871686615bbf565b82900390912095945050505050565b8082535050565b60605f808080806159b3888a018a61642b565b95509550955095509550508187106159d15794506159ed9350505050565b8387106159e55782955050505050506159ed565b509293505050505b9392505050565b5f54610100900460ff16615a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff16615b4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c1a565b61288833615212565b60655460ff16612888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c1a565b5f825f03615bce5750826159ed565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b84811015615c95576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa158015615c5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190615c8091906160e7565b87525060209095019460019384019301615be9565b5093949350505050565b5f60208284031215615caf575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114615033575f80fd5b5f60208284031215615ce9575f80fd5b6159ed82615cb6565b5f8083601f840112615d02575f80fd5b50813567ffffffffffffffff811115615d19575f80fd5b602083019150836020828501011115615d30575f80fd5b9250929050565b5f805f60408486031215615d49575f80fd5b833567ffffffffffffffff811115615d5f575f80fd5b615d6b86828701615cf2565b909790965060209590950135949350505050565b5f8060208385031215615d90575f80fd5b823567ffffffffffffffff811115615da6575f80fd5b615db285828601615cf2565b90969095509350505050565b5f60e08284031215614f6c575f80fd5b5f60608284031215614f6c575f80fd5b5f8060408385031215615def575f80fd5b823567ffffffffffffffff80821115615e06575f80fd5b615e1286838701615dbe565b93506020850135915080821115615e27575f80fd5b50615e3485828601615dce565b9150509250929050565b5f805f805f8060808789031215615e53575f80fd5b863567ffffffffffffffff80821115615e6a575f80fd5b615e768a838b01615dbe565b97506020890135915080821115615e8b575f80fd5b615e978a838b01615dce565b96506040890135915080821115615eac575f80fd5b615eb88a838b01615cf2565b90965094506060890135915080821115615ed0575f80fd5b50615edd89828a01615cf2565b979a9699509497509295939492505050565b5f805f805f8060c08789031215615f04575f80fd5b615f0d87615cb6565b9550615f1b60208801615cb6565b9450615f2960408801615cb6565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f8060408587031215615f5d575f80fd5b843567ffffffffffffffff80821115615f74575f80fd5b615f8088838901615cf2565b90965094506020870135915080821115615f98575f80fd5b50615fa587828801615cf2565b95989497509550505050565b80151581146138b2575f80fd5b5f60208284031215615fce575f80fd5b81356159ed81615fb1565b803567ffffffffffffffff81168114615033575f80fd5b5f8060408385031215616001575f80fd5b61600a83615fd9565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611b8c57611b8c616018565b81810381811115611b8c57611b8c616018565b5f6020828403121561607b575f80fd5b81516159ed81615fb1565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126160b9575f80fd5b83018035915067ffffffffffffffff8211156160d3575f80fd5b602001915036819003821315615d30575f80fd5b5f602082840312156160f7575f80fd5b5051919050565b5f6020828403121561610e575f80fd5b813561ffff811681146159ed575f80fd5b5f6020828403121561612f575f80fd5b813560ff811681146159ed575f80fd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361616f5761616f616018565b5060010190565b5f60208284031215616186575f80fd5b6159ed82615fd9565b818382375f9101908152919050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f6080820187835260206080602085015281885180845260a08601915060208a0193505f5b8181101561623c57845173ffffffffffffffffffffffffffffffffffffffff168352938301939183019160010161620a565b5050876040860152848103606086015261625781878961619e565b9a9950505050505050505050565b858152846020820152608060408201525f61628460808301858761619e565b90508260608301529695505050505050565b5f82515f5b818110156162b5576020818601810151858301520161629b565b505f920191825250919050565b8082028115828204841417611b8c57611b8c616018565b5f8261630c577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261637a575f80fd5b8135602067ffffffffffffffff808311156163975761639761633e565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156163da576163da61633e565b60405293845260208187018101949081019250878511156163f9575f80fd5b6020870191505b848210156164205761641182615cb6565b83529183019190830190616400565b979650505050505050565b5f805f805f8060c08789031215616440575f80fd5b86359550602087013567ffffffffffffffff8082111561645e575f80fd5b61646a8a838b0161636b565b9650604089013595506060890135915080821115616486575f80fd5b6164928a838b0161636b565b94506080890135935060a08901359150808211156164ae575f80fd5b506164bb89828a0161636b565b915050929550929550929556fea164736f6c6343000818000a" +var RollupDeployedBin = "0x60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610b6b578063f2fde38b14610b8a578063f8fa010f14610ba9578063fb1e8b0414610bc8575f80fd5b8063d8dc99d214610b22578063de8b303514610b37578063dff7827e14610b56575f80fd5b8063cd4edc69116100cd578063cd4edc6914610abc578063ce5db8d614610acf578063cf9a674514610ae4578063d279c19114610b03575f80fd5b8063b8d0a1b014610a5f578063bedb86fb14610a7e578063c555389214610a9d575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d3146109ed578063b348442514610a02578063b35dac4e14610a21578063b3e0a50914610a40575f80fd5b8063a479265d1461098e578063a4f209b0146109a3578063abc8d68d146109c2575f80fd5b8063910129d411610198578063910129d4146108e457806397fc007c14610915578063a3c9e94c14610934578063a415d8dc14610960575f80fd5b806388b1ea09146107d75780638da5cb5b146107f05780638f1d37761461081a575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa1461075a5780636c578c1d14610785578063715018a6146107a4578063728cdbca146107b8575f80fd5b80635f77cf1d146106d0578063612672901461071c57806367caa37a1461073b575f80fd5b806341f756da1161026e57806341f756da146105fb57806357e0af6c1461060e5780635c975abb1461062d5780635ef7a94a14610644575f80fd5b80632b7ac3f3146105695780633b70c18a146105ba5780633e001b66146105e6575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004615e36565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004615e70565b610bdd565b005b3480156103fb575f80fd5b506103ee61040a366004615ece565b610d01565b34801561041a575f80fd5b50610397610429366004615e36565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004615f16565b6110ed565b348015610470575f80fd5b506103ee61047f366004615f65565b61172f565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004615e36565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004615e36565b611ba4565b3480156104f3575f80fd5b506103c1610502366004615e36565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004615e36565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004615e36565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c546105959073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a3565b3480156105c5575f80fd5b50609b546105959073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105f1575f80fd5b506103c160aa5481565b6103ee610609366004615ff3565b611bd2565b348015610619575f80fd5b506103ee610628366004615e36565b611f65565b348015610638575f80fd5b5060655460ff16610397565b34801561064f575f80fd5b5061069a61065e366004615e36565b60a26020525f908152604090208054600182015460028301546003909301549192909173ffffffffffffffffffffffffffffffffffffffff1684565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080016103a3565b3480156106db575f80fd5b506107037f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b348015610727575f80fd5b506103ee610736366004615e36565b61202a565b348015610746575f80fd5b506103ee610755366004615ff3565b61228d565b348015610765575f80fd5b506103c1610774366004615e36565b60ab6020525f908152604090205481565b348015610790575f80fd5b506103ee61079f366004615e70565b612681565b3480156107af575f80fd5b506103ee612790565b3480156107c3575f80fd5b506103ee6107d236600461602d565b6127a3565b3480156107e2575f80fd5b5060a6546103979060ff1681565b3480156107fb575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610595565b348015610825575f80fd5b50610893610834366004615e36565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b3480156108ef575f80fd5b506103976108fe366004615e36565b5f90815260a4602052604090206003015460ff1690565b348015610920575f80fd5b506103ee61092f366004615e70565b612b6c565b34801561093f575f80fd5b506097546105959073ffffffffffffffffffffffffffffffffffffffff1681565b34801561096b575f80fd5b5061039761097a366004615e70565b609f6020525f908152604090205460ff1681565b348015610999575f80fd5b506103c160995481565b3480156109ae575f80fd5b506103ee6109bd366004615e36565b612c90565b3480156109cd575f80fd5b506103c16109dc366004615e70565b60a56020525f908152604090205481565b3480156109f8575f80fd5b506103c160a85481565b348015610a0d575f80fd5b506103ee610a1c366004616088565b612d5a565b348015610a2c575f80fd5b506103ee610a3b366004615e70565b61314f565b348015610a4b575f80fd5b506103ee610a5a366004615f16565b6131b5565b348015610a6a575f80fd5b506103ee610a79366004616088565b6135ef565b348015610a89575f80fd5b506103ee610a983660046160fc565b613692565b348015610aa8575f80fd5b506103ee610ab7366004615e36565b613825565b6103ee610aca36600461612e565b6138e2565b348015610ada575f80fd5b506103c160985481565b348015610aef575f80fd5b506103ee610afe366004615e36565b613ff7565b348015610b0e575f80fd5b506103ee610b1d366004615e70565b6141d4565b348015610b2d575f80fd5b506103c160ac5481565b348015610b42575f80fd5b50610397610b51366004615e36565b6142ba565b348015610b61575f80fd5b506103c1609a5481565b348015610b76575f80fd5b506103ee610b85366004615e36565b614311565b348015610b95575f80fd5b506103ee610ba4366004615e70565b6143ce565b348015610bb4575f80fd5b506103ee610bc3366004615e70565b614482565b348015610bd3575f80fd5b506103c160a95481565b610be5614823565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610c79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610d09614823565b5f8111610d72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c70565b5f80610d7e85856148a4565b915091505f610d91836001015160c01c90565b5f81815260a160205260409020549091508214610e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b5f60a181610e188785616183565b81526020019081526020015f205414610eb2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c70565b609d548111610f43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c70565b610f4e600182616196565b609e555b83156110e557604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610f9a816142ba565b15611020575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091610ff2908490616183565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a8541580159061109d575060a85481145b156110a7575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610f52575b505050505050565b60a85415611157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b61115f614966565b5f8061116b84846148a4565b915091505f61117e836001015160c01c90565b5f81815260a1602052604090205490915082146111f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b61120081611ba4565b611266576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c70565b61126f816142ba565b156112d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c70565b5f81815260a4602052604090206003015460ff1615611351576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c70565b5f81815260a260205260409020600101544210156113cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c70565b605983015160a05f6113de600185616196565b81526020019081526020015f205414611453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c70565b5f81815260a06020526040902054156114c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c70565b80609d5460010114611536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c70565b609d819055600160a35f61154b866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a060205260409020556115b86115ab846011015160c01c90565b600985015160c01c6149d3565b60a25f6115c6600184616196565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906116229084616196565b81526020019081526020015f205f905560ad5f6001836116429190616196565b81526020019081526020015f205f905560a45f6001836116629190616196565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61170b866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a85415611799576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b6117a1614966565b60ac54609e545f90815260a26020526040812054909142916117c39190616183565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611835573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061185991906161a9565b6118639190616183565b109050811580156118715750805b156118f2575f6118876080890160608a016161c0565b61ffff16116118f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b81806118fb5750805b611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c70565b5f61197761197260208a018a6161e1565b6148a4565b5090505f611989826001015160c01c90565b611994906001616183565b5f81815260ad60205260408120549192509015611a4e575f4915611a3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c70565b505f81815260ad6020526040902054611a69565b611a66611a5e60208c018c616242565b60ff16614a97565b90505b611a748a5f83614c06565b5f80611a808b8b6148a4565b915091505f611a93836001015160c01c90565b905080609e5414611b00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c70565b5f81815260a160205260409020548214611b76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b5f81815260a26020526040902042600190910155611b95838b8b61521f565b50505050505050505050505050565b5f81815260a2602052604081205415801590611bcc57505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611c58573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7c9190616262565b611ce2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b60a85415611d4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b611d54614966565b5f611d6561197260208401846161e1565b5090505f611d77826001015160c01c90565b611d82906001616183565b5f81815260ad602052604090205490915015611e20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610c70565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e91573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb591906161a9565b611ebf9190616183565b1015611f41575f611ed660808501606086016161c0565b61ffff1611611f41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b5f611f52611a5e6020860186616242565b9050611f5f843383614c06565b50505050565b611f6d614823565b5f81118015611f7e57506099548114155b611fe4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c70565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561204a57505f5460ff8083169116105b6120d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556121115f5460ff1690565b60ff1660021461217d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c70565b8161220a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c70565b609e545f90815260ab602052604090205461223357609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612313573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123379190616262565b61239d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b60a85415612407576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b61240f614966565b5f4915612478576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c70565b5f61248961197260208401846161e1565b5090505f61249b826001015160c01c90565b6124a6906001616183565b5f81815260ad6020526040902054909150612543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c70565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa1580156125b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125d891906161a9565b6125e29190616183565b1015612664575f6125f960808501606086016161c0565b61ffff1611612664576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b61267c83335f84815260ad6020526040902054614c06565b505050565b612689614823565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff16612717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c70565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610cf6565b612798614823565b6127a15f6153f9565b565b5f54610100900460ff16158080156127c157505f54600160ff909116105b806127da5750303b1580156127da57505f5460ff166001145b612866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156128c2575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806128f9575073ffffffffffffffffffffffffffffffffffffffff8516155b15612930576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166129ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c70565b6129b561546f565b6129bd61550d565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612b63575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612b74614823565b73ffffffffffffffffffffffffffffffffffffffff811615801590612bb45750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c70565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612c98614823565b5f81118015612ca8575060648111155b8015612cb6575060a9548114155b612d1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c70565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161201e565b60a85415612dc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b612dcc614966565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612e52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190616262565b612edc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b5f80612ee886866148a4565b915091505f612efb836001015160c01c90565b5f81815260a160205260409020549091508214612f74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b612f7d816142ba565b612fe3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c70565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161305a91616183565b11613104575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526130ff91839173ffffffffffffffffffffffffffffffffffffffff16906155ab565b612b63565b61310f83868661521f565b612b6381336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615731565b613157614823565b60aa80545f9091556131698282615817565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161201e565b6131bd614823565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea541561324e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c70565b5f8061325a84846148a4565b915091505f61326d836001015160c01c90565b905080156132d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c70565b5f6132e3846079015190565b90508061334c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c70565b600984015160c01c156133bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c70565b5f6133c7856019015190565b0361342e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c70565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461345a856039015190565b146134c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c70565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f806135fb86866148a4565b915091505f61360e836001015160c01c90565b5f81815260a160205260409020549091508214613687576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b612b6383868661521f565b61369a614823565b80156137f3576136a86158e7565b60a65460ff16156137a55760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091613709908490616183565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b6137fb61596c565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336137c8565b50565b61382d614823565b5f8111801561383e575060ac548114155b6138a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c70565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161201e565b335f908152609f602052604090205460ff1661395a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c70565b60a854156139c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b6139cc614966565b60a65460ff1615613a39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c70565b8167ffffffffffffffff16609d5410613aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a160205260409020548114613b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b613b428267ffffffffffffffff16611ba4565b613ba8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613c4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a260205260409020600101544210613cf4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c70565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d8291906161a9565b341015613deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c70565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613f5791815260200190565b60405180910390a35f609d546001613f6f9190616183565b90505b609e548111613fc7578267ffffffffffffffff168114613fb5576099545f82815260a2602052604081206001018054909190613faf908490616183565b90915550505b80613fbf8161627d565b915050613f72565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff1615801561401757505f5460ff8083169116105b6140a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017815582900361413c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c70565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b335f90815260a560205260408120549081900361424d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c70565b335f90815260a560205260408120556142668282615817565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516142ae91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611bcc5750505f90815260a46020526040902060030154610100900460ff161590565b614319614823565b5f8111801561432a57506098548114155b614390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c70565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161201e565b6143d6614823565b73ffffffffffffffffffffffffffffffffffffffff8116614479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c70565b613822816153f9565b5f54600490610100900460ff161580156144a257505f5460ff8083169116105b61452e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905573ffffffffffffffffffffffffffffffffffffffff82161580159061459957505f8273ffffffffffffffffffffffffffffffffffffffff163b115b6145ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c70565b609d54609e541461466c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c70565b60a65460ff16156146d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610c70565b60a85415614743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b60975460405173ffffffffffffffffffffffffffffffffffffffff8085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b60335473ffffffffffffffffffffffffffffffffffffffff1633146127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c70565b5f805f6148b185856159c3565b90505f8160ff165f036148d2576148c88686615a4d565b9094509050614958565b8160ff16600114806148e757508160ff166002145b156148f6576148c88686615ad0565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c70565b808420925050509250929050565b60655460ff16156127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c70565b805f036149de575050565b8082035f5b82811015611f5f576101008184038111156149fd57508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b158015614a6d575f80fd5b505af1158015614a7f573d5f803e3d5ffd5b505050506101008301925050610100810190506149e3565b5f81600203614b40575f6040515f5b804980614ab35750614ac2565b60208202830152600101614aa6565b602081028083209201604052909250905080614b3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c70565b50919050565b60014915614bd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c70565b5f4915614bde575f49611bcc565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002614c156020850185616242565b60ff161115614c80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c70565b6080830135614ceb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c70565b60a0830135614d56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c70565b5f80614d6861197260208701876161e1565b915091505f614d7b836001015160c01c90565b90505f60a181614d8c846001616183565b81526020019081526020015f205414614e01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c70565b609e548114614e6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c70565b5f81815260a160205260409020548214614ee2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c70565b5f81815260ab6020526040902054608087013514614f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c70565b5f614f6b846011015160c01c90565b90505f614f97614f8160608a0160408b016162b4565b614f9160808b0160608c016161c0565b84615b3d565b9050614fa96080890160608a016161c0565b60019384019361ffff91909116929092019160f990614fcb60208b018b616242565b60ff1610614fd857506101015b604080518281019091529550614ffd86614ff560208c018c616242565b60ff16615b81565b60c084901b600187015261502b8661501b60808c0160608d016161c0565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161507b60208b018b616242565b60ff16106150ad576150ad8661509760608c0160408d016162b4565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156151165760a7545f90815260a46020526040902060020154609954429161510991616183565b6151139190616196565b90505b604051806080016040528042815260200182609854426151369190616183565b6151409190616183565b815260200161515560608d0160408e016162b4565b67ffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b80615286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c70565b5f615295846001015160c01c90565b90505f6152a3856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006152d2876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a8486153a1885160f81c90565b858888866040518663ffffffff1660e01b81526004016153c59594939291906162cd565b5f6040518083038186803b1580156153db575f80fd5b505afa1580156153ed573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16615505576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1615b88565b5f54610100900460ff166155a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1615c48565b60a88390555f83815260a460205260408082205460975491517fc96be4cb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af115801561563f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061566391906161a9565b5f86815260a46020526040902060010154909150615682908290616183565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a5909152812080549091906156ce908490616183565b90915550506040516156e1908490616330565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490615755908461635c565b61575f9190616373565b905061576b8183616196565b60aa5f82825461577b9190616183565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a56020526040812080548392906157b4908490616183565b90915550506040516157c7908490616330565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b80156158e3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615873576040519150601f19603f3d011682016040523d82523d5f602084013e615878565b606091505b505090508061267c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c70565b5050565b6158ef614966565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586159423390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b615974615ce7565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33615942565b5f81615a2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c70565b82825f818110615a3d57615a3d6163ab565b919091013560f81c949350505050565b5f8160f9811015615aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c70565b6040519150808483378082016040529250929050565b5f816101018114615aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c70565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101615b728161ffff871686615d53565b82900390912095945050505050565b8082535050565b5f54610100900460ff16615c1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff16615cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1336153f9565b60655460ff166127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c70565b5f825f03615d62575082615e2f565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b84811015615e29576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa158015615df0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190615e1491906161a9565b87525060209095019460019384019301615d7d565b50849150505b9392505050565b5f60208284031215615e46575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614c01575f80fd5b5f60208284031215615e80575f80fd5b615e2f82615e4d565b5f8083601f840112615e99575f80fd5b50813567ffffffffffffffff811115615eb0575f80fd5b602083019150836020828501011115615ec7575f80fd5b9250929050565b5f805f60408486031215615ee0575f80fd5b833567ffffffffffffffff811115615ef6575f80fd5b615f0286828701615e89565b909790965060209590950135949350505050565b5f8060208385031215615f27575f80fd5b823567ffffffffffffffff811115615f3d575f80fd5b615f4985828601615e89565b90969095509350505050565b5f60e08284031215614b3a575f80fd5b5f805f805f60608688031215615f79575f80fd5b853567ffffffffffffffff80821115615f90575f80fd5b615f9c89838a01615f55565b96506020880135915080821115615fb1575f80fd5b615fbd89838a01615e89565b90965094506040880135915080821115615fd5575f80fd5b50615fe288828901615e89565b969995985093965092949392505050565b5f60208284031215616003575f80fd5b813567ffffffffffffffff811115616019575f80fd5b61602584828501615f55565b949350505050565b5f805f805f8060c08789031215616042575f80fd5b61604b87615e4d565b955061605960208801615e4d565b945061606760408801615e4d565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561609b575f80fd5b843567ffffffffffffffff808211156160b2575f80fd5b6160be88838901615e89565b909650945060208701359150808211156160d6575f80fd5b506160e387828801615e89565b95989497509550505050565b8015158114613822575f80fd5b5f6020828403121561610c575f80fd5b8135615e2f816160ef565b803567ffffffffffffffff81168114614c01575f80fd5b5f806040838503121561613f575f80fd5b61614883616117565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611bcc57611bcc616156565b81810381811115611bcc57611bcc616156565b5f602082840312156161b9575f80fd5b5051919050565b5f602082840312156161d0575f80fd5b813561ffff81168114615e2f575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112616214575f80fd5b83018035915067ffffffffffffffff82111561622e575f80fd5b602001915036819003821315615ec7575f80fd5b5f60208284031215616252575f80fd5b813560ff81168114615e2f575f80fd5b5f60208284031215616272575f80fd5b8151615e2f816160ef565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036162ad576162ad616156565b5060010190565b5f602082840312156162c4575f80fd5b615e2f82616117565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b8181101561634f5760208186018101518583015201616335565b505f920191825250919050565b8082028115828204841417611bcc57611bcc616156565b5f826163a6577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a" func init() { if err := json.Unmarshal([]byte(RollupStorageLayoutJSON), RollupStorageLayout); err != nil { diff --git a/bindings/bindings/submitter.go b/bindings/bindings/submitter.go new file mode 100644 index 000000000..c929a6c9e --- /dev/null +++ b/bindings/bindings/submitter.go @@ -0,0 +1,2502 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/morph-l2/go-ethereum" + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// SubmitterMetaData contains all meta data concerning the Submitter contract. +var SubmitterMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"MinimumStakeUpdated\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"addSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rollupContract_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardPercentage_\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"isActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"registered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"removeSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setMinimumStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"stakeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"withdrawing\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isWithdrawing\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561000f575f80fd5b5061001861001d565b6100d9565b5f54610100900460ff16156100885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100d7575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611d06806100e65f395ff3fe608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611bc0565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611be0565b6105d2565b3480156101ef575f80fd5b5061019b6101fe366004611be0565b610678565b61019b61071e565b348015610216575f80fd5b50610239610225366004611bc0565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b6108b3565b348015610268575f80fd5b506101b2610277366004611bc0565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b6109f0565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611bc0565b610a01565b348015610326575f80fd5b5061019b610335366004611bc0565b610a92565b348015610345575f80fd5b5061019b610354366004611be0565b610c83565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611bc0565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611bc0565b610d36565b3480156103f2575f80fd5b506101b2610401366004611bc0565b610ece565b348015610411575f80fd5b5061019b610420366004611bc0565b611085565b348015610430575f80fd5b5061019b61043f366004611bf7565b6111b1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611bc0565b6115f9565b610480611693565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b61057a5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105da611693565b5f811180156105eb57506098548114155b6106375760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610680611693565b5f8111801561069157506099548114155b6106dd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107266116fa565b335f818152609c602052604090205460ff168015610769575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107b55760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546107e5903490611c6d565b90505f341180156107f857506098548110155b6108445760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108b16001606555565b565b335f818152609c602052604090205460ff1680156108f6575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610925575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109715760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b6109f8611693565b6108b15f61175a565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a5a575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a8c575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a9a6116fa565b3373ffffffffffffffffffffffffffffffffffffffff8216610afe5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b725760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e6700000000000000000000000000000000006044820152606401610571565b610b7a6117d0565b610bc65760405162461bcd60e51b815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e656400000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e909252909120805460ff19169055610c0d83826118d8565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610c6c91815260200190565b60405180910390a35050610c806001606555565b50565b610c8b611693565b5f81118015610c9b575060648111155b8015610ca95750609a548114155b610cf55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610d3e611693565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610d97575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610de35760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610e8a5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e602052604090819020805460ff19166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e4490610e819084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f4d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610571565b610f556116fa565b73ffffffffffffffffffffffffffffffffffffffff8216610f7757505f611076565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216909155609a54606490610fd59083611c80565b610fdf9190611c97565b9150610feb8282611ccf565b609b5f828254610ffb9190611c6d565b90915550506097546110239073ffffffffffffffffffffffffffffffffffffffff16836118d8565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110806001606555565b919050565b61108d611693565b6110956116fa565b73ffffffffffffffffffffffffffffffffffffffff81166110f85760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b609b54806111485760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610571565b5f609b5561115682826118d8565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161119e91815260200190565b60405180910390a250610c806001606555565b5f54610100900460ff16158080156111cf57505f54600160ff909116105b806111e85750303b1580156111e857505f5460ff166001145b61125a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610571565b5f805460ff191660011790558015611298575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166112fb5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff85161580159061133657505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113825760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610571565b5f84116113d15760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b5f83116114205760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b5f82118015611430575060648211155b61147c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b611484611994565b61148c611a18565b6114958661175a565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156115f1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611601611693565b73ffffffffffffffffffffffffffffffffffffffff811661168a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610571565b610c808161175a565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108b15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610571565b60026065540361174c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610571565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611840573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118649190611ce2565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118d19190611ce2565b1491505090565b805f036118e3575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611939576040519150601f19603f3d011682016040523d82523d5f602084013e61193e565b606091505b505090508061198f5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610571565b505050565b5f54610100900460ff16611a105760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611a9c565b5f54610100900460ff16611a945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611b21565b5f54610100900460ff16611b185760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b13361175a565b5f54610100900460ff166117535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b803573ffffffffffffffffffffffffffffffffffffffff81168114611080575f80fd5b5f60208284031215611bd0575f80fd5b611bd982611b9d565b9392505050565b5f60208284031215611bf0575f80fd5b5035919050565b5f805f805f60a08688031215611c0b575f80fd5b611c1486611b9d565b9450611c2260208701611b9d565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8c57610a8c611c40565b8082028115828204841417610a8c57610a8c611c40565b5f82611cca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8c57610a8c611c40565b5f60208284031215611cf2575f80fd5b505191905056fea164736f6c6343000818000a", +} + +// SubmitterABI is the input ABI used to generate the binding from. +// Deprecated: Use SubmitterMetaData.ABI instead. +var SubmitterABI = SubmitterMetaData.ABI + +// SubmitterBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SubmitterMetaData.Bin instead. +var SubmitterBin = SubmitterMetaData.Bin + +// DeploySubmitter deploys a new Ethereum contract, binding an instance of Submitter to it. +func DeploySubmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Submitter, error) { + parsed, err := SubmitterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SubmitterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil +} + +// Submitter is an auto generated Go binding around an Ethereum contract. +type Submitter struct { + SubmitterCaller // Read-only binding to the contract + SubmitterTransactor // Write-only binding to the contract + SubmitterFilterer // Log filterer for contract events +} + +// SubmitterCaller is an auto generated read-only Go binding around an Ethereum contract. +type SubmitterCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SubmitterTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SubmitterFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SubmitterSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SubmitterSession struct { + Contract *Submitter // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SubmitterCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SubmitterCallerSession struct { + Contract *SubmitterCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SubmitterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SubmitterTransactorSession struct { + Contract *SubmitterTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SubmitterRaw is an auto generated low-level Go binding around an Ethereum contract. +type SubmitterRaw struct { + Contract *Submitter // Generic contract binding to access the raw methods on +} + +// SubmitterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SubmitterCallerRaw struct { + Contract *SubmitterCaller // Generic read-only contract binding to access the raw methods on +} + +// SubmitterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SubmitterTransactorRaw struct { + Contract *SubmitterTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSubmitter creates a new instance of Submitter, bound to a specific deployed contract. +func NewSubmitter(address common.Address, backend bind.ContractBackend) (*Submitter, error) { + contract, err := bindSubmitter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Submitter{SubmitterCaller: SubmitterCaller{contract: contract}, SubmitterTransactor: SubmitterTransactor{contract: contract}, SubmitterFilterer: SubmitterFilterer{contract: contract}}, nil +} + +// NewSubmitterCaller creates a new read-only instance of Submitter, bound to a specific deployed contract. +func NewSubmitterCaller(address common.Address, caller bind.ContractCaller) (*SubmitterCaller, error) { + contract, err := bindSubmitter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SubmitterCaller{contract: contract}, nil +} + +// NewSubmitterTransactor creates a new write-only instance of Submitter, bound to a specific deployed contract. +func NewSubmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*SubmitterTransactor, error) { + contract, err := bindSubmitter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SubmitterTransactor{contract: contract}, nil +} + +// NewSubmitterFilterer creates a new log filterer instance of Submitter, bound to a specific deployed contract. +func NewSubmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*SubmitterFilterer, error) { + contract, err := bindSubmitter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SubmitterFilterer{contract: contract}, nil +} + +// bindSubmitter binds a generic wrapper to an already deployed contract. +func bindSubmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SubmitterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Submitter *SubmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Submitter.Contract.SubmitterCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Submitter *SubmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.Contract.SubmitterTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Submitter *SubmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Submitter.Contract.SubmitterTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Submitter *SubmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Submitter.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Submitter *SubmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Submitter *SubmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Submitter.Contract.contract.Transact(opts, method, params...) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterCaller) ChallengeDeposit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "challengeDeposit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterSession) ChallengeDeposit() (*big.Int, error) { + return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) +} + +// ChallengeDeposit is a free data retrieval call binding the contract method 0x0d13fd7b. +// +// Solidity: function challengeDeposit() view returns(uint256) +func (_Submitter *SubmitterCallerSession) ChallengeDeposit() (*big.Int, error) { + return _Submitter.Contract.ChallengeDeposit(&_Submitter.CallOpts) +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterCaller) IsActive(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "isActive", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterSession) IsActive(submitter common.Address) (bool, error) { + return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) +} + +// IsActive is a free data retrieval call binding the contract method 0x9f8a13d7. +// +// Solidity: function isActive(address submitter) view returns(bool) +func (_Submitter *SubmitterCallerSession) IsActive(submitter common.Address) (bool, error) { + return _Submitter.Contract.IsActive(&_Submitter.CallOpts, submitter) +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterCaller) MinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "minimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterSession) MinimumStake() (*big.Int, error) { + return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) +} + +// MinimumStake is a free data retrieval call binding the contract method 0xec5ffac2. +// +// Solidity: function minimumStake() view returns(uint256) +func (_Submitter *SubmitterCallerSession) MinimumStake() (*big.Int, error) { + return _Submitter.Contract.MinimumStake(&_Submitter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterSession) Owner() (common.Address, error) { + return _Submitter.Contract.Owner(&_Submitter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Submitter *SubmitterCallerSession) Owner() (common.Address, error) { + return _Submitter.Contract.Owner(&_Submitter.CallOpts) +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterCaller) Registered(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "registered", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterSession) Registered(submitter common.Address) (bool, error) { + return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) +} + +// Registered is a free data retrieval call binding the contract method 0xb2dd5c07. +// +// Solidity: function registered(address submitter) view returns(bool isRegistered) +func (_Submitter *SubmitterCallerSession) Registered(submitter common.Address) (bool, error) { + return _Submitter.Contract.Registered(&_Submitter.CallOpts, submitter) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterCaller) RewardPercentage(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "rewardPercentage") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterSession) RewardPercentage() (*big.Int, error) { + return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) +} + +// RewardPercentage is a free data retrieval call binding the contract method 0x52d472eb. +// +// Solidity: function rewardPercentage() view returns(uint256) +func (_Submitter *SubmitterCallerSession) RewardPercentage() (*big.Int, error) { + return _Submitter.Contract.RewardPercentage(&_Submitter.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterCaller) RollupContract(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "rollupContract") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterSession) RollupContract() (common.Address, error) { + return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) +} + +// RollupContract is a free data retrieval call binding the contract method 0xbfa02ba9. +// +// Solidity: function rollupContract() view returns(address) +func (_Submitter *SubmitterCallerSession) RollupContract() (common.Address, error) { + return _Submitter.Contract.RollupContract(&_Submitter.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterCaller) SlashRemaining(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "slashRemaining") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterSession) SlashRemaining() (*big.Int, error) { + return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) +} + +// SlashRemaining is a free data retrieval call binding the contract method 0xab8c53dc. +// +// Solidity: function slashRemaining() view returns(uint256) +func (_Submitter *SubmitterCallerSession) SlashRemaining() (*big.Int, error) { + return _Submitter.Contract.SlashRemaining(&_Submitter.CallOpts) +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCaller) StakeOf(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "stakeOf", submitter) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterSession) StakeOf(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) +} + +// StakeOf is a free data retrieval call binding the contract method 0x42623360. +// +// Solidity: function stakeOf(address submitter) view returns(uint256 amount) +func (_Submitter *SubmitterCallerSession) StakeOf(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) +} + +// Withdrawing is a free data retrieval call binding the contract method 0x3baf3a2f. +// +// Solidity: function withdrawing(address submitter) view returns(bool isWithdrawing) +func (_Submitter *SubmitterCaller) Withdrawing(opts *bind.CallOpts, submitter common.Address) (bool, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "withdrawing", submitter) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Withdrawing is a free data retrieval call binding the contract method 0x3baf3a2f. +// +// Solidity: function withdrawing(address submitter) view returns(bool isWithdrawing) +func (_Submitter *SubmitterSession) Withdrawing(submitter common.Address) (bool, error) { + return _Submitter.Contract.Withdrawing(&_Submitter.CallOpts, submitter) +} + +// Withdrawing is a free data retrieval call binding the contract method 0x3baf3a2f. +// +// Solidity: function withdrawing(address submitter) view returns(bool isWithdrawing) +func (_Submitter *SubmitterCallerSession) Withdrawing(submitter common.Address) (bool, error) { + return _Submitter.Contract.Withdrawing(&_Submitter.CallOpts, submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactor) AddSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "addSubmitter", submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) +} + +// AddSubmitter is a paid mutator transaction binding the contract method 0x072900f9. +// +// Solidity: function addSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactorSession) AddSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.AddSubmitter(&_Submitter.TransactOpts, submitter) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterTransactor) ClaimSlashRemaining(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "claimSlashRemaining", receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) +} + +// ClaimSlashRemaining is a paid mutator transaction binding the contract method 0xcde4cd11. +// +// Solidity: function claimSlashRemaining(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) ClaimSlashRemaining(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimSlashRemaining(&_Submitter.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterTransactor) ClaimWithdrawal(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "claimWithdrawal", receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) +} + +// ClaimWithdrawal is a paid mutator transaction binding the contract method 0xa3066aab. +// +// Solidity: function claimWithdrawal(address receiver) returns() +func (_Submitter *SubmitterTransactorSession) ClaimWithdrawal(receiver common.Address) (*types.Transaction, error) { + return _Submitter.Contract.ClaimWithdrawal(&_Submitter.TransactOpts, receiver) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterTransactor) Initialize(opts *bind.TransactOpts, owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "initialize", owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// Initialize is a paid mutator transaction binding the contract method 0xd13f90b4. +// +// Solidity: function initialize(address owner_, address rollupContract_, uint256 minimumStake_, uint256 challengeDeposit_, uint256 rewardPercentage_) returns() +func (_Submitter *SubmitterTransactorSession) Initialize(owner_ common.Address, rollupContract_ common.Address, minimumStake_ *big.Int, challengeDeposit_ *big.Int, rewardPercentage_ *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.Initialize(&_Submitter.TransactOpts, owner_, rollupContract_, minimumStake_, challengeDeposit_, rewardPercentage_) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactor) RemoveSubmitter(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "removeSubmitter", submitter) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) +} + +// RemoveSubmitter is a paid mutator transaction binding the contract method 0xc36f41e2. +// +// Solidity: function removeSubmitter(address submitter) returns() +func (_Submitter *SubmitterTransactorSession) RemoveSubmitter(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.RemoveSubmitter(&_Submitter.TransactOpts, submitter) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterSession) RenounceOwnership() (*types.Transaction, error) { + return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_Submitter *SubmitterTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _Submitter.Contract.RenounceOwnership(&_Submitter.TransactOpts) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterTransactor) SetMinimumStake(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "setMinimumStake", value) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) +} + +// SetMinimumStake is a paid mutator transaction binding the contract method 0x233e9903. +// +// Solidity: function setMinimumStake(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) SetMinimumStake(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.SetMinimumStake(&_Submitter.TransactOpts, value) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterTransactor) Slash(opts *bind.TransactOpts, submitter common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "slash", submitter) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterSession) Slash(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) +} + +// Slash is a paid mutator transaction binding the contract method 0xc96be4cb. +// +// Solidity: function slash(address submitter) returns(uint256 reward) +func (_Submitter *SubmitterTransactorSession) Slash(submitter common.Address) (*types.Transaction, error) { + return _Submitter.Contract.Slash(&_Submitter.TransactOpts, submitter) +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterTransactor) Stake(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "stake") +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterSession) Stake() (*types.Transaction, error) { + return _Submitter.Contract.Stake(&_Submitter.TransactOpts) +} + +// Stake is a paid mutator transaction binding the contract method 0x3a4b66f1. +// +// Solidity: function stake() payable returns() +func (_Submitter *SubmitterTransactorSession) Stake() (*types.Transaction, error) { + return _Submitter.Contract.Stake(&_Submitter.TransactOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_Submitter *SubmitterTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _Submitter.Contract.TransferOwnership(&_Submitter.TransactOpts, newOwner) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterTransactor) UpdateChallengeDeposit(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "updateChallengeDeposit", value) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) +} + +// UpdateChallengeDeposit is a paid mutator transaction binding the contract method 0x35928991. +// +// Solidity: function updateChallengeDeposit(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) UpdateChallengeDeposit(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateChallengeDeposit(&_Submitter.TransactOpts, value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterTransactor) UpdateRewardPercentage(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "updateRewardPercentage", value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) +} + +// UpdateRewardPercentage is a paid mutator transaction binding the contract method 0xa4f209b0. +// +// Solidity: function updateRewardPercentage(uint256 value) returns() +func (_Submitter *SubmitterTransactorSession) UpdateRewardPercentage(value *big.Int) (*types.Transaction, error) { + return _Submitter.Contract.UpdateRewardPercentage(&_Submitter.TransactOpts, value) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_Submitter *SubmitterTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Submitter.contract.Transact(opts, "withdraw") +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_Submitter *SubmitterSession) Withdraw() (*types.Transaction, error) { + return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts) +} + +// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b. +// +// Solidity: function withdraw() returns() +func (_Submitter *SubmitterTransactorSession) Withdraw() (*types.Transaction, error) { + return _Submitter.Contract.Withdraw(&_Submitter.TransactOpts) +} + +// SubmitterChallengeDepositUpdatedIterator is returned from FilterChallengeDepositUpdated and is used to iterate over the raw logs and unpacked data for ChallengeDepositUpdated events raised by the Submitter contract. +type SubmitterChallengeDepositUpdatedIterator struct { + Event *SubmitterChallengeDepositUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterChallengeDepositUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterChallengeDepositUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterChallengeDepositUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterChallengeDepositUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterChallengeDepositUpdated represents a ChallengeDepositUpdated event raised by the Submitter contract. +type SubmitterChallengeDepositUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChallengeDepositUpdated is a free log retrieval operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterChallengeDepositUpdated(opts *bind.FilterOpts) (*SubmitterChallengeDepositUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return &SubmitterChallengeDepositUpdatedIterator{contract: _Submitter.contract, event: "ChallengeDepositUpdated", logs: logs, sub: sub}, nil +} + +// WatchChallengeDepositUpdated is a free log subscription operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchChallengeDepositUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterChallengeDepositUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "ChallengeDepositUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterChallengeDepositUpdated) + if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChallengeDepositUpdated is a log parse operation binding the contract event 0x36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55. +// +// Solidity: event ChallengeDepositUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseChallengeDepositUpdated(log types.Log) (*SubmitterChallengeDepositUpdated, error) { + event := new(SubmitterChallengeDepositUpdated) + if err := _Submitter.contract.UnpackLog(event, "ChallengeDepositUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Submitter contract. +type SubmitterInitializedIterator struct { + Event *SubmitterInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterInitialized represents a Initialized event raised by the Submitter contract. +type SubmitterInitialized struct { + Version uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) FilterInitialized(opts *bind.FilterOpts) (*SubmitterInitializedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &SubmitterInitializedIterator{contract: _Submitter.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *SubmitterInitialized) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterInitialized) + if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_Submitter *SubmitterFilterer) ParseInitialized(log types.Log) (*SubmitterInitialized, error) { + event := new(SubmitterInitialized) + if err := _Submitter.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterMinimumStakeUpdatedIterator is returned from FilterMinimumStakeUpdated and is used to iterate over the raw logs and unpacked data for MinimumStakeUpdated events raised by the Submitter contract. +type SubmitterMinimumStakeUpdatedIterator struct { + Event *SubmitterMinimumStakeUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterMinimumStakeUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterMinimumStakeUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterMinimumStakeUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterMinimumStakeUpdated represents a MinimumStakeUpdated event raised by the Submitter contract. +type SubmitterMinimumStakeUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMinimumStakeUpdated is a free log retrieval operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterMinimumStakeUpdated(opts *bind.FilterOpts) (*SubmitterMinimumStakeUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "MinimumStakeUpdated") + if err != nil { + return nil, err + } + return &SubmitterMinimumStakeUpdatedIterator{contract: _Submitter.contract, event: "MinimumStakeUpdated", logs: logs, sub: sub}, nil +} + +// WatchMinimumStakeUpdated is a free log subscription operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchMinimumStakeUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterMinimumStakeUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "MinimumStakeUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterMinimumStakeUpdated) + if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMinimumStakeUpdated is a log parse operation binding the contract event 0xd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49. +// +// Solidity: event MinimumStakeUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseMinimumStakeUpdated(log types.Log) (*SubmitterMinimumStakeUpdated, error) { + event := new(SubmitterMinimumStakeUpdated) + if err := _Submitter.contract.UnpackLog(event, "MinimumStakeUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Submitter contract. +type SubmitterOwnershipTransferredIterator struct { + Event *SubmitterOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterOwnershipTransferred represents a OwnershipTransferred event raised by the Submitter contract. +type SubmitterOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*SubmitterOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &SubmitterOwnershipTransferredIterator{contract: _Submitter.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SubmitterOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterOwnershipTransferred) + if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Submitter *SubmitterFilterer) ParseOwnershipTransferred(log types.Log) (*SubmitterOwnershipTransferred, error) { + event := new(SubmitterOwnershipTransferred) + if err := _Submitter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterRewardPercentageUpdatedIterator is returned from FilterRewardPercentageUpdated and is used to iterate over the raw logs and unpacked data for RewardPercentageUpdated events raised by the Submitter contract. +type SubmitterRewardPercentageUpdatedIterator struct { + Event *SubmitterRewardPercentageUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterRewardPercentageUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterRewardPercentageUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterRewardPercentageUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterRewardPercentageUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterRewardPercentageUpdated represents a RewardPercentageUpdated event raised by the Submitter contract. +type SubmitterRewardPercentageUpdated struct { + OldValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRewardPercentageUpdated is a free log retrieval operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) FilterRewardPercentageUpdated(opts *bind.FilterOpts) (*SubmitterRewardPercentageUpdatedIterator, error) { + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return &SubmitterRewardPercentageUpdatedIterator{contract: _Submitter.contract, event: "RewardPercentageUpdated", logs: logs, sub: sub}, nil +} + +// WatchRewardPercentageUpdated is a free log subscription operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) WatchRewardPercentageUpdated(opts *bind.WatchOpts, sink chan<- *SubmitterRewardPercentageUpdated) (event.Subscription, error) { + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "RewardPercentageUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterRewardPercentageUpdated) + if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRewardPercentageUpdated is a log parse operation binding the contract event 0xa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba. +// +// Solidity: event RewardPercentageUpdated(uint256 oldValue, uint256 newValue) +func (_Submitter *SubmitterFilterer) ParseRewardPercentageUpdated(log types.Log) (*SubmitterRewardPercentageUpdated, error) { + event := new(SubmitterRewardPercentageUpdated) + if err := _Submitter.contract.UnpackLog(event, "RewardPercentageUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSlashRemainingClaimedIterator is returned from FilterSlashRemainingClaimed and is used to iterate over the raw logs and unpacked data for SlashRemainingClaimed events raised by the Submitter contract. +type SubmitterSlashRemainingClaimedIterator struct { + Event *SubmitterSlashRemainingClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSlashRemainingClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashRemainingClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSlashRemainingClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSlashRemainingClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSlashRemainingClaimed represents a SlashRemainingClaimed event raised by the Submitter contract. +type SubmitterSlashRemainingClaimed struct { + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashRemainingClaimed is a free log retrieval operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterSlashRemainingClaimed(opts *bind.FilterOpts, receiver []common.Address) (*SubmitterSlashRemainingClaimedIterator, error) { + + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SlashRemainingClaimed", receiverRule) + if err != nil { + return nil, err + } + return &SubmitterSlashRemainingClaimedIterator{contract: _Submitter.contract, event: "SlashRemainingClaimed", logs: logs, sub: sub}, nil +} + +// WatchSlashRemainingClaimed is a free log subscription operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchSlashRemainingClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashRemainingClaimed, receiver []common.Address) (event.Subscription, error) { + + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SlashRemainingClaimed", receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSlashRemainingClaimed) + if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashRemainingClaimed is a log parse operation binding the contract event 0xa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9. +// +// Solidity: event SlashRemainingClaimed(address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseSlashRemainingClaimed(log types.Log) (*SubmitterSlashRemainingClaimed, error) { + event := new(SubmitterSlashRemainingClaimed) + if err := _Submitter.contract.UnpackLog(event, "SlashRemainingClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSlashedIterator is returned from FilterSlashed and is used to iterate over the raw logs and unpacked data for Slashed events raised by the Submitter contract. +type SubmitterSlashedIterator struct { + Event *SubmitterSlashed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSlashedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSlashed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSlashedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSlashedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSlashed represents a Slashed event raised by the Submitter contract. +type SubmitterSlashed struct { + Submitter common.Address + Amount *big.Int + Reward *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSlashed is a free log retrieval operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) FilterSlashed(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSlashedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Slashed", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSlashedIterator{contract: _Submitter.contract, event: "Slashed", logs: logs, sub: sub}, nil +} + +// WatchSlashed is a free log subscription operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) WatchSlashed(opts *bind.WatchOpts, sink chan<- *SubmitterSlashed, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Slashed", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSlashed) + if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSlashed is a log parse operation binding the contract event 0x45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596. +// +// Solidity: event Slashed(address indexed submitter, uint256 amount, uint256 reward) +func (_Submitter *SubmitterFilterer) ParseSlashed(log types.Log) (*SubmitterSlashed, error) { + event := new(SubmitterSlashed) + if err := _Submitter.contract.UnpackLog(event, "Slashed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterStakedIterator is returned from FilterStaked and is used to iterate over the raw logs and unpacked data for Staked events raised by the Submitter contract. +type SubmitterStakedIterator struct { + Event *SubmitterStaked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterStakedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterStaked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterStaked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterStakedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterStakedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterStaked represents a Staked event raised by the Submitter contract. +type SubmitterStaked struct { + Submitter common.Address + Amount *big.Int + Total *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterStaked is a free log retrieval operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) FilterStaked(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterStakedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "Staked", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterStakedIterator{contract: _Submitter.contract, event: "Staked", logs: logs, sub: sub}, nil +} + +// WatchStaked is a free log subscription operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) WatchStaked(opts *bind.WatchOpts, sink chan<- *SubmitterStaked, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "Staked", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterStaked) + if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseStaked is a log parse operation binding the contract event 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90. +// +// Solidity: event Staked(address indexed submitter, uint256 amount, uint256 total) +func (_Submitter *SubmitterFilterer) ParseStaked(log types.Log) (*SubmitterStaked, error) { + event := new(SubmitterStaked) + if err := _Submitter.contract.UnpackLog(event, "Staked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSubmitterAddedIterator is returned from FilterSubmitterAdded and is used to iterate over the raw logs and unpacked data for SubmitterAdded events raised by the Submitter contract. +type SubmitterSubmitterAddedIterator struct { + Event *SubmitterSubmitterAdded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSubmitterAddedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSubmitterAddedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSubmitterAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSubmitterAdded represents a SubmitterAdded event raised by the Submitter contract. +type SubmitterSubmitterAdded struct { + Submitter common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterAdded is a free log retrieval operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) FilterSubmitterAdded(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterAddedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterAdded", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSubmitterAddedIterator{contract: _Submitter.contract, event: "SubmitterAdded", logs: logs, sub: sub}, nil +} + +// WatchSubmitterAdded is a free log subscription operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) WatchSubmitterAdded(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterAdded, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterAdded", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSubmitterAdded) + if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterAdded is a log parse operation binding the contract event 0xb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b. +// +// Solidity: event SubmitterAdded(address indexed submitter) +func (_Submitter *SubmitterFilterer) ParseSubmitterAdded(log types.Log) (*SubmitterSubmitterAdded, error) { + event := new(SubmitterSubmitterAdded) + if err := _Submitter.contract.UnpackLog(event, "SubmitterAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterSubmitterRemovedIterator is returned from FilterSubmitterRemoved and is used to iterate over the raw logs and unpacked data for SubmitterRemoved events raised by the Submitter contract. +type SubmitterSubmitterRemovedIterator struct { + Event *SubmitterSubmitterRemoved // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterSubmitterRemovedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterSubmitterRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterSubmitterRemovedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterSubmitterRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterSubmitterRemoved represents a SubmitterRemoved event raised by the Submitter contract. +type SubmitterSubmitterRemoved struct { + Submitter common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitterRemoved is a free log retrieval operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) FilterSubmitterRemoved(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterSubmitterRemovedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "SubmitterRemoved", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterSubmitterRemovedIterator{contract: _Submitter.contract, event: "SubmitterRemoved", logs: logs, sub: sub}, nil +} + +// WatchSubmitterRemoved is a free log subscription operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) WatchSubmitterRemoved(opts *bind.WatchOpts, sink chan<- *SubmitterSubmitterRemoved, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "SubmitterRemoved", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterSubmitterRemoved) + if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitterRemoved is a log parse operation binding the contract event 0xf84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1. +// +// Solidity: event SubmitterRemoved(address indexed submitter) +func (_Submitter *SubmitterFilterer) ParseSubmitterRemoved(log types.Log) (*SubmitterSubmitterRemoved, error) { + event := new(SubmitterSubmitterRemoved) + if err := _Submitter.contract.UnpackLog(event, "SubmitterRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterWithdrawalClaimedIterator is returned from FilterWithdrawalClaimed and is used to iterate over the raw logs and unpacked data for WithdrawalClaimed events raised by the Submitter contract. +type SubmitterWithdrawalClaimedIterator struct { + Event *SubmitterWithdrawalClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterWithdrawalClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterWithdrawalClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterWithdrawalClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterWithdrawalClaimed represents a WithdrawalClaimed event raised by the Submitter contract. +type SubmitterWithdrawalClaimed struct { + Submitter common.Address + Receiver common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalClaimed is a free log retrieval operation binding the contract event 0x8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef3. +// +// Solidity: event WithdrawalClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterWithdrawalClaimed(opts *bind.FilterOpts, submitter []common.Address, receiver []common.Address) (*SubmitterWithdrawalClaimedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalClaimed", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return &SubmitterWithdrawalClaimedIterator{contract: _Submitter.contract, event: "WithdrawalClaimed", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalClaimed is a free log subscription operation binding the contract event 0x8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef3. +// +// Solidity: event WithdrawalClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchWithdrawalClaimed(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalClaimed, submitter []common.Address, receiver []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + var receiverRule []interface{} + for _, receiverItem := range receiver { + receiverRule = append(receiverRule, receiverItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalClaimed", submitterRule, receiverRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterWithdrawalClaimed) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalClaimed is a log parse operation binding the contract event 0x8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef3. +// +// Solidity: event WithdrawalClaimed(address indexed submitter, address indexed receiver, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseWithdrawalClaimed(log types.Log) (*SubmitterWithdrawalClaimed, error) { + event := new(SubmitterWithdrawalClaimed) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SubmitterWithdrawalRequestedIterator is returned from FilterWithdrawalRequested and is used to iterate over the raw logs and unpacked data for WithdrawalRequested events raised by the Submitter contract. +type SubmitterWithdrawalRequestedIterator struct { + Event *SubmitterWithdrawalRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SubmitterWithdrawalRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SubmitterWithdrawalRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SubmitterWithdrawalRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SubmitterWithdrawalRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SubmitterWithdrawalRequested represents a WithdrawalRequested event raised by the Submitter contract. +type SubmitterWithdrawalRequested struct { + Submitter common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalRequested is a free log retrieval operation binding the contract event 0xe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44. +// +// Solidity: event WithdrawalRequested(address indexed submitter, uint256 amount) +func (_Submitter *SubmitterFilterer) FilterWithdrawalRequested(opts *bind.FilterOpts, submitter []common.Address) (*SubmitterWithdrawalRequestedIterator, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.FilterLogs(opts, "WithdrawalRequested", submitterRule) + if err != nil { + return nil, err + } + return &SubmitterWithdrawalRequestedIterator{contract: _Submitter.contract, event: "WithdrawalRequested", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalRequested is a free log subscription operation binding the contract event 0xe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44. +// +// Solidity: event WithdrawalRequested(address indexed submitter, uint256 amount) +func (_Submitter *SubmitterFilterer) WatchWithdrawalRequested(opts *bind.WatchOpts, sink chan<- *SubmitterWithdrawalRequested, submitter []common.Address) (event.Subscription, error) { + + var submitterRule []interface{} + for _, submitterItem := range submitter { + submitterRule = append(submitterRule, submitterItem) + } + + logs, sub, err := _Submitter.contract.WatchLogs(opts, "WithdrawalRequested", submitterRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SubmitterWithdrawalRequested) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalRequested is a log parse operation binding the contract event 0xe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44. +// +// Solidity: event WithdrawalRequested(address indexed submitter, uint256 amount) +func (_Submitter *SubmitterFilterer) ParseWithdrawalRequested(log types.Log) (*SubmitterWithdrawalRequested, error) { + event := new(SubmitterWithdrawalRequested) + if err := _Submitter.contract.UnpackLog(event, "WithdrawalRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/bindings/bindings/submitter_more.go b/bindings/bindings/submitter_more.go new file mode 100644 index 000000000..e2538faf0 --- /dev/null +++ b/bindings/bindings/submitter_more.go @@ -0,0 +1,25 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "encoding/json" + + "morph-l2/bindings/solc" +) + +const SubmitterStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1016_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1016_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"minimumStake\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"registered\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"stakeOf\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"withdrawing\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_array(t_uint256)1017_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1016_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1017_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" + +var SubmitterStorageLayout = new(solc.StorageLayout) + +var SubmitterDeployedBin = "0x608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611f6a565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611f8a565b61060a565b3480156101ef575f80fd5b5061019b6101fe366004611f8a565b6106ca565b61019b61078a565b348015610216575f80fd5b50610239610225366004611f6a565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b610953565b348015610268575f80fd5b506101b2610277366004611f6a565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b610ac8565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611f6a565b610ad9565b348015610326575f80fd5b5061019b610335366004611f6a565b610b6a565b348015610345575f80fd5b5061019b610354366004611f8a565b610dc7565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611f6a565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611f6a565b610e94565b3480156103f2575f80fd5b506101b2610401366004611f6a565b611082565b348015610411575f80fd5b5061019b610420366004611f6a565b611271565b348015610430575f80fd5b5061019b61043f366004611fa1565b6113d1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611f6a565b6118d3565b610480611987565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b610594576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b610612611987565b5f8111801561062357506098548114155b610689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b650000000000000000000000604482015260640161058b565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b6106d2611987565b5f811180156106e357506099548114155b610749576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f73697400000000000000604482015260640161058b565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610792611a08565b335f818152609c602052604090205460ff1680156107d5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b61083b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6e6f74207374616b6561626c6500000000000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604081205461086b903490612017565b90505f3411801561087e57506098548110155b6108e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b6500000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506109516001606555565b565b335f818152609c602052604090205460ff168015610996575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b80156109c5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b610a2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420776974686472617761626c6500000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b610ad0611987565b6109515f611a82565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610b32575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610b64575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610b72611a08565b3373ffffffffffffffffffffffffffffffffffffffff8216610bf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c696420726563656976657200000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f74207769746864726177696e670000000000000000000000000000000000604482015260640161058b565b610c86611af8565b610cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e65640000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610d518382611c00565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610db091815260200190565b60405180910390a35050610dc46001606555565b50565b610dcf611987565b5f81118015610ddf575060648111155b8015610ded5750609a548114155b610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e7461676500000000000000604482015260640161058b565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610e9c611987565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610ef5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d6974746572000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609d909152902054801561103e5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44906110359084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e7472616374000000000000000000000000604482015260640161058b565b611123611a08565b73ffffffffffffffffffffffffffffffffffffffff821661114557505f611262565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c845282852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690915591859055609e90935292208054909216909155609a546064906111c1908361202a565b6111cb9190612041565b91506111d78282612079565b609b5f8282546111e79190612017565b909155505060975461120f9073ffffffffffffffffffffffffffffffffffffffff1683611c00565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61126c6001606555565b919050565b611279611987565b611281611a08565b73ffffffffffffffffffffffffffffffffffffffff81166112fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c696420726563656976657200000000000000000000000000000000604482015260640161058b565b609b5480611368576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e670000000000000000000000000000604482015260640161058b565b5f609b556113768282611c00565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9826040516113be91815260200190565b60405180910390a250610dc46001606555565b5f54610100900460ff16158080156113ef57505f54600160ff909116105b806114085750303b15801561140857505f5460ff166001145b611494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161058b565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156114f0575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861661156d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c6964206f776e657200000000000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff8516158015906115a857505f8573ffffffffffffffffffffffffffffffffffffffff163b115b61160e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e7472616374000000000000000000604482015260640161058b565b5f8411611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b650000000000000000000000604482015260640161058b565b5f83116116e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f73697400000000000000604482015260640161058b565b5f821180156116f0575060648211155b611756576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e7461676500000000000000604482015260640161058b565b61175e611cd6565b611766611d74565b61176f86611a82565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156118cb575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6118db611987565b73ffffffffffffffffffffffffffffffffffffffff811661197e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161058b565b610dc481611a82565b60335473ffffffffffffffffffffffffffffffffffffffff163314610951576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161058b565b600260655403611a74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161058b565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611b68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8c919061208c565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf9919061208c565b1491505090565b805f03611c0b575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611c61576040519150601f19603f3d011682016040523d82523d5f602084013e611c66565b606091505b5050905080611cd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161058b565b505050565b5f54610100900460ff16611d6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b610951611e12565b5f54610100900460ff16611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b610951611eb1565b5f54610100900460ff16611ea8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b61095133611a82565b5f54610100900460ff16611a7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b803573ffffffffffffffffffffffffffffffffffffffff8116811461126c575f80fd5b5f60208284031215611f7a575f80fd5b611f8382611f47565b9392505050565b5f60208284031215611f9a575f80fd5b5035919050565b5f805f805f60a08688031215611fb5575f80fd5b611fbe86611f47565b9450611fcc60208701611f47565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610b6457610b64611fea565b8082028115828204841417610b6457610b64611fea565b5f82612074577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610b6457610b64611fea565b5f6020828403121561209c575f80fd5b505191905056fea164736f6c6343000818000a" + +func init() { + if err := json.Unmarshal([]byte(SubmitterStorageLayoutJSON), SubmitterStorageLayout); err != nil { + panic(err) + } + + layouts["Submitter"] = SubmitterStorageLayout + deployedBytecodes["Submitter"] = SubmitterDeployedBin +} diff --git a/contracts/deploy/013-DeployProxys.ts b/contracts/deploy/013-DeployProxys.ts index 6b3a4a5ce..3a5023a67 100644 --- a/contracts/deploy/013-DeployProxys.ts +++ b/contracts/deploy/013-DeployProxys.ts @@ -47,7 +47,7 @@ export const deployContractProxies = async ( ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName + const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -106,9 +106,9 @@ export const deployContractProxies = async ( return err } - // ************************ staking contracts deploy ************************ - // StakingProxy deploy - err = await deployContractProxyByStorageName(hre, path, deployer, L1StakingProxyStorageName) + // ************************ batch submitter contract deploy ************************ + // SubmitterProxy deploy + err = await deployContractProxyByStorageName(hre, path, deployer, SubmitterProxyStorageName) if (err != "") { return err } @@ -281,7 +281,7 @@ export const deployContractProxiesConcurrently = async ( const proxyStorageNames = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.L1StakingProxyStorageName, + ProxyStorageName.SubmitterProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, @@ -326,4 +326,4 @@ export const deployContractProxiesConcurrently = async ( }; -export default deployContractProxies \ No newline at end of file +export default deployContractProxies diff --git a/contracts/deploy/014-DeployImpls.ts b/contracts/deploy/014-DeployImpls.ts index b32613018..7d4fbd2be 100644 --- a/contracts/deploy/014-DeployImpls.ts +++ b/contracts/deploy/014-DeployImpls.ts @@ -23,7 +23,7 @@ export const deployContractImplsConcurrently = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1StakingFactoryName = ContractFactoryName.L1Staking + const SubmitterFactoryName = ContractFactoryName.Submitter const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -41,7 +41,7 @@ export const deployContractImplsConcurrently = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const StakingImplStorageName = ImplStorageName.L1StakingStorageName + const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -80,18 +80,6 @@ export const deployContractImplsConcurrently = async ( await contract.deployed() console.log("%s=%s ; TX_HASH: %s", storageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - if (factoryName == L1StakingFactoryName) { - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) - } const blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) console.log(`Deployment completed for: ${storageName}`); @@ -120,7 +108,7 @@ export const deployContractImplsConcurrently = async ( deployPromises.push(deployContract(L1ERC721GatewayFactoryName, L1ERC721GatewayImplStorageName)) deployPromises.push(deployContract(L1ERC1155GatewayFactoryName, L1ERC1155GatewayImplStorageName)) - deployPromises.push(deployContract(L1StakingFactoryName, StakingImplStorageName, [L1CrossDomainMessengerProxyAddress])) + deployPromises.push(deployContract(SubmitterFactoryName, SubmitterImplStorageName)) // L1Sequencer deploy (no constructor args) const L1SequencerFactoryName = ContractFactoryName.L1Sequencer @@ -151,7 +139,7 @@ export const deployContractImpls = async ( ): Promise => { // factory name const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1StakingFactoryName = ContractFactoryName.L1Staking + const SubmitterFactoryName = ContractFactoryName.Submitter const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle const RollupFactoryName = ContractFactoryName.Rollup const WhitelistFactoryName = ContractFactoryName.Whitelist @@ -169,7 +157,7 @@ export const deployContractImpls = async ( // implement storage name const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const StakingImplStorageName = ImplStorageName.L1StakingStorageName + const SubmitterImplStorageName = ImplStorageName.SubmitterStorageName const L1MessageQueueWithGasPriceOracleImplStorageName = ImplStorageName.L1MessageQueueWithGasPriceOracle const RollupImplStorageName = ImplStorageName.RollupStorageName const L1GatewayRouterImplStorageName = ImplStorageName.L1GatewayRouterStorageName @@ -364,25 +352,15 @@ export const deployContractImpls = async ( return err } - // ************************ staking contracts deploy ************************ - // Staking deploy - Factory = await hre.ethers.getContractFactory(L1StakingFactoryName) - contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) + // ************************ batch submitter contract deploy ************************ + // Submitter deploy + Factory = await hre.ethers.getContractFactory(SubmitterFactoryName) + contract = await Factory.deploy() await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", StakingImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) + console.log("%s=%s ; TX_HASH: %s", SubmitterImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); blockNumber = await hre.ethers.provider.getBlockNumber() console.log("BLOCK_NUMBER: %s", blockNumber) - err = await storage(path, StakingImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) + err = await storage(path, SubmitterImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) if (err != '') { return err } diff --git a/contracts/deploy/015-SubmitterInit.ts b/contracts/deploy/015-SubmitterInit.ts new file mode 100644 index 000000000..a061378cf --- /dev/null +++ b/contracts/deploy/015-SubmitterInit.ts @@ -0,0 +1,78 @@ +import "@nomiclabs/hardhat-ethers"; + +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ethers } from "ethers"; + +import { assertContractVariable, awaitCondition, getContractAddressByName } from "../src/deploy-utils"; +import { ContractFactoryName, ImplStorageName, ProxyStorageName } from "../src/types"; + +export const SubmitterInit = async ( + hre: HardhatRuntimeEnvironment, + path: string, + deployer: any, + config: any +): Promise => { + const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); + const implementationAddress = getContractAddressByName(path, ImplStorageName.SubmitterStorageName); + const rollupAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName); + const owner: string = config.submitterOwner; + const minimumStake: number = config.submitterMinimumStake; + const challengeDeposit: number = config.submitterChallengeDeposit; + const rewardPercentage: number = config.submitterRewardPercentage; + + if ( + !ethers.utils.isAddress(proxyAddress) || + !ethers.utils.isAddress(implementationAddress) || + !ethers.utils.isAddress(rollupAddress) || + !ethers.utils.isAddress(owner) || + minimumStake <= 0 || + challengeDeposit <= 0 || + rewardPercentage <= 0 || + rewardPercentage > 100 + ) { + return "invalid Submitter configuration"; + } + + const proxy = await hre.ethers.getContractAt( + ContractFactoryName.DefaultProxyInterface, + proxyAddress, + deployer + ); + const factory = await hre.ethers.getContractFactory(ContractFactoryName.Submitter); + if ((await proxy.implementation()).toLowerCase() !== implementationAddress.toLowerCase()) { + const initializer = factory.interface.encodeFunctionData("initialize", [ + owner, + rollupAddress, + hre.ethers.utils.parseEther(minimumStake.toString()), + hre.ethers.utils.parseEther(challengeDeposit.toString()), + rewardPercentage, + ]); + await (await proxy.upgradeToAndCall(implementationAddress, initializer)).wait(); + } + + await awaitCondition( + async () => (await proxy.implementation()).toLowerCase() === implementationAddress.toLowerCase(), + 3000, + 1000 + ); + + const submitter = new ethers.Contract(proxyAddress, factory.interface, deployer); + await assertContractVariable(submitter, "owner", owner); + await assertContractVariable(submitter, "rollupContract", rollupAddress); + await assertContractVariable( + submitter, + "minimumStake", + hre.ethers.utils.parseEther(minimumStake.toString()) + ); + await assertContractVariable( + submitter, + "challengeDeposit", + hre.ethers.utils.parseEther(challengeDeposit.toString()) + ); + await assertContractVariable(submitter, "rewardPercentage", rewardPercentage); + + console.log(`Submitter proxy initialized at ${proxyAddress}`); + return ""; +}; + +export default SubmitterInit; diff --git a/contracts/deploy/016-RollupInit.ts b/contracts/deploy/016-RollupInit.ts index 82036f186..9043d2b34 100644 --- a/contracts/deploy/016-RollupInit.ts +++ b/contracts/deploy/016-RollupInit.ts @@ -23,7 +23,7 @@ export const RollupInit = async ( // Load the contracts we need to interact with. const ZkEvmVerifierV1Address = getContractAddressByName(path, ImplStorageName.ZkEvmVerifierV1StorageName) const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName(path, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName) - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) + const SubmitterProxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName) // Rollup config const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) @@ -60,7 +60,7 @@ export const RollupInit = async ( if (!ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || !ethers.utils.isAddress(MultipleVersionRollupVerifierContract.address) - || !ethers.utils.isAddress(L1StakingProxyAddress) + || !ethers.utils.isAddress(SubmitterProxyAddress) ) { console.error('please check your address') @@ -70,7 +70,7 @@ export const RollupInit = async ( await IRollupProxy.upgradeToAndCall( RollupImplAddress, RollupFactory.interface.encodeFunctionData('initialize', [ - L1StakingProxyAddress, + SubmitterProxyAddress, L1MessageQueueWithGasPriceOracleProxyAddress, MultipleVersionRollupVerifierContract.address, finalizationPeriodSeconds, @@ -97,8 +97,8 @@ export const RollupInit = async ( ) await assertContractVariable( contractTmp, - 'l1StakingContract', - L1StakingProxyAddress + 'submitterContract', + SubmitterProxyAddress ) await assertContractVariable( contractTmp, diff --git a/contracts/deploy/018-StakingInit.ts b/contracts/deploy/018-StakingInit.ts deleted file mode 100644 index 5cf151a42..000000000 --- a/contracts/deploy/018-StakingInit.ts +++ /dev/null @@ -1,128 +0,0 @@ -import "@nomiclabs/hardhat-web3"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; - -import { - HardhatRuntimeEnvironment -} from 'hardhat/types'; -import { assertContractVariable, getContractAddressByName, awaitCondition } from "../src/deploy-utils"; -import { ethers } from 'ethers' - -import { - ImplStorageName, - ProxyStorageName, - ContractFactoryName, -} from "../src/types" - -export const StakingInit = async ( - hre: HardhatRuntimeEnvironment, - path: string, - deployer: any, - configTmp: any -): Promise => { - // Load the contracts we need to interact with. - const RollupProxyAddress = getContractAddressByName(path, ProxyStorageName.RollupProxyStorageName) - - // Staking config - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingImplAddress = getContractAddressByName(path, ImplStorageName.L1StakingStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - - const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) - if ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() !== L1StakingImplAddress.toLocaleLowerCase() - ) { - console.log('Upgrading the Staking proxy...') - const admin: string = configTmp.contractAdmin - const stakingChallengerRewardPercentage: number = configTmp.stakingChallengerRewardPercentage - const limit: number = configTmp.stakingMinDeposit - const challengeDeposit: number = configTmp.stakingChallengeDeposit - const lock: number = configTmp.stakingLockNumber - const gasLimitAdd: number = configTmp.stakingCrossChainGaslimitAdd - const gasLimitRemove: number = configTmp.stakingCrossChainGaslimitRemove - - if (!ethers.utils.isAddress(admin) - || lock <= 0 - || limit <= 0 - || challengeDeposit <= 0 - || gasLimitAdd <= 0 - || gasLimitRemove <= 0 - || stakingChallengerRewardPercentage > 100 - || stakingChallengerRewardPercentage <= 0 - ) { - console.error('please check your address') - return '' - } - - // Upgrade and initialize the proxy. - await IL1StakingProxy.upgradeToAndCall( - L1StakingImplAddress, - L1StakingFactory.interface.encodeFunctionData('initialize', [ - RollupProxyAddress, - hre.ethers.utils.parseEther(limit.toString()), - hre.ethers.utils.parseEther(challengeDeposit.toString()), - lock.toString(), - stakingChallengerRewardPercentage, - gasLimitAdd, - gasLimitRemove, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - - const contractTmp = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - deployer, - ) - - await assertContractVariable( - contractTmp, - 'rollupContract', - RollupProxyAddress - ) - await assertContractVariable( - contractTmp, - 'rewardPercentage', - stakingChallengerRewardPercentage - ) - await assertContractVariable( - contractTmp, - 'stakingValue', - hre.ethers.utils.parseEther(limit.toString()) - ) - await assertContractVariable( - contractTmp, - 'withdrawalLockBlocks', - lock.toString() - ) - await assertContractVariable( - contractTmp, - 'gasLimitAddStaker', - gasLimitAdd - ) - await assertContractVariable( - contractTmp, - 'gasLimitRemoveStakers', - gasLimitRemove - ) - await assertContractVariable( - contractTmp, - 'owner', - await deployer.getAddress(), - ) - // Wait for the transaction to execute properly. - console.log('StakingProxy upgrade success') - } - return '' -} - -export default StakingInit diff --git a/contracts/deploy/019-AdminTransfer.ts b/contracts/deploy/019-AdminTransfer.ts index a0cd1b58a..f60016b73 100644 --- a/contracts/deploy/019-AdminTransfer.ts +++ b/contracts/deploy/019-AdminTransfer.ts @@ -108,7 +108,7 @@ export const AdminTransferConcurrently = async ( const contractsToChange = [ ProxyStorageName.L1CrossDomainMessengerProxyStorageName, ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName, - ProxyStorageName.L1StakingProxyStorageName, + ProxyStorageName.SubmitterProxyStorageName, ProxyStorageName.L1SequencerProxyStorageName, // Added L1Sequencer ProxyStorageName.RollupProxyStorageName, ProxyStorageName.L1GatewayRouterProxyStorageName, @@ -159,7 +159,7 @@ export const AdminTransfer = async ( const L1MessageQueueWithGasPriceOracleProxyStorageName = ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName + const SubmitterProxyStorageName = ProxyStorageName.SubmitterProxyStorageName const L1SequencerProxyStorageName = ProxyStorageName.L1SequencerProxyStorageName const L1GatewayRouterProxyStorageName = ProxyStorageName.L1GatewayRouterProxyStorageName @@ -187,9 +187,9 @@ export const AdminTransfer = async ( return err } - // ************************ staking contracts admin change ************************ - // StakingProxy admin change - err = await AdminTransferByProxyStorageName(hre, path, deployer, L1StakingProxyStorageName) + // ************************ batch submitter contract admin change ************************ + // SubmitterProxy admin change + err = await AdminTransferByProxyStorageName(hre, path, deployer, SubmitterProxyStorageName) if (err != '') { return err } @@ -277,4 +277,4 @@ export const AdminTransfer = async ( return '' } -module.exports = { AdminTransfer, AdminTransferByProxyStorageName, AdminTransferConcurrently, AdminTransferByProxyStorageNameConcurrently } \ No newline at end of file +module.exports = { AdminTransfer, AdminTransferByProxyStorageName, AdminTransferConcurrently, AdminTransferByProxyStorageNameConcurrently } diff --git a/contracts/deploy/020-ContractInit.ts b/contracts/deploy/020-ContractInit.ts index 96bf3637b..22ed49663 100644 --- a/contracts/deploy/020-ContractInit.ts +++ b/contracts/deploy/020-ContractInit.ts @@ -31,20 +31,6 @@ export const ContractInit = async ( let rec = await res.wait() console.log(`set base fee ${rec.status === 1} setL2BaseFee(${await GasPriceOracle.l2BaseFee()}) gwei`) - const WhitelistImplAddress = getContractAddressByName(path, ImplStorageName.Whitelist) - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) - let addList = [L1StakingProxyAddress] - res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) - rec = await res.wait() - for (let i = 0; i < addList.length; i++) { - let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) - if (res != true) { - console.error('whitelist check failed') - return '' - } - } - console.log(`add ${addList} to whitelist success`) } // ------------------ rollup init ----------------- @@ -54,14 +40,11 @@ export const ContractInit = async ( // import genesis batch const batchHeader: string = config.batchHeader - // submitter and challenger - const submitter: string = config.rollupProposer + // challenger const challenger: string = config.rollupChallenger const rollupDelayPeriod: number = config.rollupDelayPeriod - if (!ethers.utils.isAddress(submitter) - || !ethers.utils.isAddress(challenger) - ) { + if (!ethers.utils.isAddress(challenger)) { console.error('please check your address') return '' } @@ -85,29 +68,6 @@ export const ContractInit = async ( console.log(`initialize3(%s) ${rec.status == 1 ? "success" : "failed"}`) } - // ------------------ staking init ----------------- - { - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) - const whiteListAdd = config.l2SequencerAddresses - console.log("Add sequencer address to white list ", config.l2SequencerAddresses) - // set sequencer to white list - await L1Staking.updateWhitelist(whiteListAdd, []) - for (let i = 0; i < config.l2SequencerAddresses.length; i++) { - // Wait for the transaction to execute properly. - await awaitCondition( - async () => { - return ( - await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true - ) - }, - 3000, - 1000 - ) - console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) - } - } - // ------------------ router init ----------------- { const L1WETHAddress = getContractAddressByName(path, ImplStorageName.WETH) diff --git a/contracts/deploy/021-StakingRegister.ts b/contracts/deploy/021-StakingRegister.ts deleted file mode 100644 index 9e69e0bf8..000000000 --- a/contracts/deploy/021-StakingRegister.ts +++ /dev/null @@ -1,57 +0,0 @@ -import "@nomiclabs/hardhat-web3"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; - -import { - HardhatRuntimeEnvironment -} from 'hardhat/types'; -import { getContractAddressByName, awaitCondition } from "../src/deploy-utils"; -import { ethers } from 'ethers' -import { - ProxyStorageName, - ContractFactoryName, -} from "../src/types" - -const two = BigInt(2) -const gwei = BigInt(1e9) -const eth = gwei * gwei - -export const StakingRegister = async ( - hre: HardhatRuntimeEnvironment, - path: string, - signer: any, - tmKey: string, - blsKey: string -): Promise => { - const L1StakingProxyAddress = getContractAddressByName(path, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - - const StakingProxyWithSigner = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - signer, - ) - - // just for devnet register value may set params to config - const response = await StakingProxyWithSigner.register(tmKey, blsKey, { - value: eth - }) - console.log(`Transaction hash (on L1): ${response.hash}`) - const receipt = await response.wait() - console.log('Transaction in L1 height', receipt.blockNumber) - - await awaitCondition( - async () => { - const sequencerInfo = (await StakingProxyWithSigner.stakers(signer.address)) - if (sequencerInfo && sequencerInfo.tmKey === tmKey) { - return true - } - return false - }, - 30000, - 1000 - ) - return '' -} - -export default StakingRegister \ No newline at end of file diff --git a/contracts/deploy/021-SubmitterRegister.ts b/contracts/deploy/021-SubmitterRegister.ts new file mode 100644 index 000000000..76411b7e2 --- /dev/null +++ b/contracts/deploy/021-SubmitterRegister.ts @@ -0,0 +1,45 @@ +import "@nomiclabs/hardhat-ethers"; + +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ethers } from "ethers"; + +import { getContractAddressByName } from "../src/deploy-utils"; +import { ContractFactoryName, ProxyStorageName } from "../src/types"; + +export const SubmitterRegister = async ( + hre: HardhatRuntimeEnvironment, + path: string, + ownerSigner: any, + submitterSigner: any +): Promise => { + const proxyAddress = getContractAddressByName(path, ProxyStorageName.SubmitterProxyStorageName); + if (!ethers.utils.isAddress(proxyAddress)) return "invalid Submitter proxy address"; + + const ownerView = await hre.ethers.getContractAt( + ContractFactoryName.Submitter, + proxyAddress, + ownerSigner + ); + const ownerAddress = await ownerSigner.getAddress(); + if ((await ownerView.owner()).toLowerCase() !== ownerAddress.toLowerCase()) { + return "registration signer is not Submitter owner"; + } + + const account = await submitterSigner.getAddress(); + if (!(await ownerView.registered(account))) { + await (await ownerView.addSubmitter(account)).wait(); + } + + const submitterView = ownerView.connect(submitterSigner); + const minimumStake = await submitterView.minimumStake(); + const currentStake = await submitterView.stakeOf(account); + if (currentStake.lt(minimumStake)) { + await (await submitterView.stake({ value: minimumStake.sub(currentStake) })).wait(); + } + if (!(await submitterView.isActive(account))) return "Submitter did not become active"; + + console.log(`Submitter ${account} registered and active with stake ${await submitterView.stakeOf(account)}`); + return ""; +}; + +export default SubmitterRegister; diff --git a/contracts/deploy/index.ts b/contracts/deploy/index.ts index a30ab90fb..18dde9082 100644 --- a/contracts/deploy/index.ts +++ b/contracts/deploy/index.ts @@ -3,13 +3,13 @@ import deployEmptyContract from './011-EmptyContract' import {deployContractProxies,deployContractProxiesConcurrently} from './013-DeployProxys' import deployZkEvmVerifierV1 from './012-Verifier' import {deployContractImpls, deployContractImplsConcurrently} from './014-DeployImpls' +import SubmitterInit from './015-SubmitterInit' import MessengerInit from './015-MessengerInit' import RollupInit from './016-RollupInit' import GatewayInit from './017-GatewayInit' -import StakingInit from './018-StakingInit' import {AdminTransfer,AdminTransferByProxyStorageName, AdminTransferConcurrently} from './019-AdminTransfer' import ContractInit from './020-ContractInit' -import StakingRegister from './021-StakingRegister' +import SubmitterRegister from './021-SubmitterRegister' import SequencerInit from './022-SequencerInit' @@ -21,14 +21,14 @@ export { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, + SubmitterInit, MessengerInit, RollupInit, GatewayInit, - StakingInit, AdminTransfer, AdminTransferByProxyStorageName, AdminTransferConcurrently, ContractInit, - StakingRegister, + SubmitterRegister, SequencerInit -} \ No newline at end of file +} diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index c60bf6ec7..02e5d030d 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -10,12 +10,12 @@ import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from "hardhat/builtin-tasks/ta import { subtask } from "hardhat/config"; + import "./tasks/deploy" import "./tasks/overflow_test" import "./tasks/check" import "./tasks/query" import "./tasks/proxy_upgrade" -import "./tasks/staking_upgrade" import "./tasks/verifier_upgrade" import "./tasks/token_deploy" import "./tasks/mainnet_upgrade" @@ -51,7 +51,8 @@ module.exports = { abiExporter: { path: './abi', runOnCompile: true, - clear: true, + // Keep immutable upgrade-boundary ABIs under abi/archive. + clear: false, }, bytecodeExporter: { path: './data', @@ -156,4 +157,4 @@ module.exports = { artifacts: "./artifacts", deployConfig: './src/deploy-config', } -} \ No newline at end of file +} diff --git a/contracts/package.json b/contracts/package.json index 810c56de1..7bf7d938c 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -23,9 +23,10 @@ "test": "yarn test:hardhat && yarn test:forge", "clean": "yarn clean:build && yarn clean:compile && yarn clean:tsc", "clean:build": "rm -rf ./dist ./cache ./cache-hardhat ./node_modules ./logs", - "clean:compile": "rm -rf ./idea ./forge_artifacts ./abi ./artifacts ./typechain-types ./forge-artifacts", + "clean:compile": "rm -rf ./idea ./forge_artifacts ./artifacts ./typechain-types ./forge-artifacts && node scripts/clean-generated-abi.js", "clean:tsc": "rm -rf ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts", "typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'", + "verify:abi-archive": "node scripts/verify-abi-archive.js", "deploy:devnetL1": "rm -f devnetL1.json && hardhat deploy --network l1 --storagepath devnetL1.json", "initialize:devnetL1": "hardhat initialize --network l1 --storagepath devnetL1.json", "register:devnetL1": "hardhat register --network l1 --storagepath devnetL1.json", diff --git a/contracts/scripts/clean-generated-abi.js b/contracts/scripts/clean-generated-abi.js new file mode 100644 index 000000000..c43402d14 --- /dev/null +++ b/contracts/scripts/clean-generated-abi.js @@ -0,0 +1,16 @@ +const fs = require('fs') +const path = require('path') + +const { archiveDir, verifyAbiArchive } = require('./verify-abi-archive') + +verifyAbiArchive() + +const abiDir = path.dirname(archiveDir) +for (const entry of fs.readdirSync(abiDir, { withFileTypes: true })) { + if (entry.name === path.basename(archiveDir)) { + continue + } + fs.rmSync(path.join(abiDir, entry.name), { recursive: true, force: true }) +} + +verifyAbiArchive() diff --git a/contracts/scripts/verify-abi-archive.js b/contracts/scripts/verify-abi-archive.js new file mode 100644 index 000000000..db6527658 --- /dev/null +++ b/contracts/scripts/verify-abi-archive.js @@ -0,0 +1,36 @@ +const crypto = require('crypto') +const fs = require('fs') +const path = require('path') + +const archiveDir = path.resolve(__dirname, '..', 'abi', 'archive') +const manifestPath = path.join(archiveDir, 'manifest.json') + +function verifyAbiArchive() { + if (!fs.existsSync(manifestPath)) { + throw new Error(`frozen ABI manifest is missing: ${manifestPath}`) + } + + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) + for (const [relativePath, expectedHash] of Object.entries(manifest.artifacts)) { + const artifactPath = path.resolve(archiveDir, relativePath) + if (!fs.existsSync(artifactPath)) { + throw new Error(`frozen ABI artifact is missing: ${artifactPath}`) + } + const actualHash = crypto + .createHash('sha256') + .update(fs.readFileSync(artifactPath)) + .digest('hex') + if (actualHash !== expectedHash) { + throw new Error( + `frozen ABI hash mismatch for ${relativePath}: expected ${expectedHash}, got ${actualHash}` + ) + } + } +} + +if (require.main === module) { + verifyAbiArchive() + console.log('Frozen ABI archive hashes verified') +} + +module.exports = { archiveDir, verifyAbiArchive } diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index 353d9ced9..82fce91b7 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -23,22 +23,17 @@ const config = { proofRewardPercent: 70, // challenge config // TODO to be removed later - rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', + batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], rollupChallenger: '0x48445d5DDb25a4f23C6d85D87f15B39Fe94e6867', // genesis config rollupGenesisStateRoot: '', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterOwner: '0x4844c339e748fD44825856E5B877a7A9B5BcE559', + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index d589f50a6..365f94604 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -24,22 +24,17 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - rollupProposer: '0x48446b07A04307F320fa34790116d73aD4A51810', + batchSubmitterAddresses: ['0x48446b07A04307F320fa34790116d73aD4A51810'], rollupChallenger: '0x2910DB00C9537B90337b40D9732f4c356cbb84D0', // genesis config batchHeader: '00000000000000000000000000000000000000000000000000aa0feb482ae04f2a6b6b422932b5a2d537cd657ceb83008e87fce6ed6d290031010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000000a31941eb1853862c0c38f378eb0c519e9e66f0942e39b47dca38c0437ab6b3e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterOwner: '0x291046850908e59B33b1758045882e9FDcfcBD1E', + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x48446b07A04307F320fa34790116d73aD4A51810", diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index 285ca9c59..e25eac54c 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -26,21 +26,16 @@ const config = { rollupDelayPeriod: 86400, // challenge config - rollupProposer: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', + batchSubmitterAddresses: ['0x70997970C51812dc3A010C7d01b50e0d17dc79C8'], rollupChallenger: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65', // genesis config batchHeader: '0x00000000000000000000000000000000000000000000000000886e14341b355178d11a2c9f985f60a1a195973078b688a11aeaebb0c95db595010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401400000000000000000000000000000000000000000000000000000000000000002d20dde82426d971e398b3cba11ebb60d0d740b799f85e2f95fd12a1faad8e2f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 100, + // submitter initialize config + submitterOwner: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 100, // register sequencers l2SequencerAddresses: [ "0x783698dCDEBdc96785c5c60ED96113612bA09c2b", diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index b0740d0b9..6e32dbf5c 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -21,21 +21,16 @@ const config = { rollupProofWindow: 86400, proofRewardPercent: 70, // challenge config - rollupProposer: '0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d', + batchSubmitterAddresses: ['0x7161aE5B767Df97BAc34e5776311Ded4Cb01691d'], rollupChallenger: '0x71616250f7CAaa8a5DC295dc5851D6b1E49188a7', // genesis config batchHeader: '', - // staking config - // staking Cross-Chain config - stakingCrossChainGaslimitAdd: 1000000, - stakingCrossChainGaslimitRemove: 8000000, - - // staking initialize config - stakingLockNumber: 3, - stakingChallengeDeposit: 1, // 1 ether - stakingMinDeposit: 1, // 1 ether - stakingChallengerRewardPercentage: 50, + // submitter initialize config + submitterOwner: '0x7161DB99e6ffA72053f0817aBfaF2fDb4ab6ccC8', + submitterChallengeDeposit: 1, // 1 ether + submitterMinimumStake: 1, // 1 ether + submitterRewardPercentage: 50, // register sequencers l2SequencerAddresses: [ "0x25d36d94b64165f72a817ae0ff9bad2ce6914c70", diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 3657c5811..47be72f0a 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -22,16 +22,17 @@ const config = { rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, - rollupProposer: '0x77774B33aFa9Ecef8835D25ff749ff84950e83af', + batchSubmitterAddresses: ['0x77774B33aFa9Ecef8835D25ff749ff84950e83af'], rollupChallenger: '0x77776ab9Ed7479Ff446f1E3135145e245f2B71B1', rollupGenesisStateRoot: '', withdrawRoot: '', batchHeader: '', finalizationPeriodSeconds: 600, - stakingSequencerSize: 7, - stakingLockNumber: 3, - stakingMinDeposit: 0.1, + submitterOwner: '0x77778E169A7A162aA0D926B0C1a1C0541Ed9E570', + submitterMinimumStake: 0.1, + submitterChallengeDeposit: 0.1, + submitterRewardPercentage: 100, baseFeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', l1FeeVaultRecipient: '0x77772Fb3715C4B8FC621e23Eda5ABbb34a9D6EAd', diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index 8e0c9786f..95c1934d2 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -18,14 +18,15 @@ const config = { rollupProofWindow: 100, rollupGenesisBlockNumber: 0, proofRewardPercent: 70, - rollupProposer: '0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3', + batchSubmitterAddresses: ['0xE70a4102e4caA3d9B8968FFb142E6A2ceFd22Ec3'], rollupChallenger: '0xF730477971E88b3162ed7FD950Be63474975bdC3', rollupGenesisStateRoot: '', finalizationPeriodSeconds: 2, - stakingMinDeposit: 1, - stakingSequencerSize: 3, - stakingLockNumber: 3, + submitterOwner: '0xD77c708607e72f520c2841E359cF54fca75d9C04', + submitterMinimumStake: 1, + submitterChallengeDeposit: 1, + submitterRewardPercentage: 100, /** * Only used for SystemConfig * --------from-------- diff --git a/contracts/src/types.ts b/contracts/src/types.ts index 7e518addd..4c2275d9c 100644 --- a/contracts/src/types.ts +++ b/contracts/src/types.ts @@ -16,8 +16,8 @@ const ContractFactoryName = { Rollup: 'Rollup', ZkEvmVerifierV1: 'ZkEvmVerifierV1', MultipleVersionRollupVerifier: 'MultipleVersionRollupVerifier', - // staking - L1Staking: 'L1Staking', + // batch submitter + Submitter: 'Submitter', // L1 sequencer L1Sequencer: 'L1Sequencer', // gateway @@ -40,8 +40,8 @@ const ProxyStorageName = { L1MessageQueueWithGasPriceOracleProxyStorageName: 'Proxy__L1MessageQueueWithGasPriceOracle', // rollup RollupProxyStorageName: 'Proxy__Rollup', - // staking - L1StakingProxyStorageName: 'Proxy__L1Staking', + // batch submitter + SubmitterProxyStorageName: 'Proxy__Submitter', // L1 sequencer L1SequencerProxyStorageName: 'Proxy__L1Sequencer', // gateway @@ -73,8 +73,8 @@ const ImplStorageName = { RollupStorageName: 'Impl__Rollup', ZkEvmVerifierV1StorageName: 'Impl__ZkEvmVerifierV1', MultipleVersionRollupVerifierStorageName: 'Impl__MultipleVersionRollupVerifier', - // staking - L1StakingStorageName: 'Impl__L1Staking', + // batch submitter + SubmitterStorageName: 'Impl__Submitter', // L1 sequencer L1SequencerStorageName: 'Impl__L1Sequencer', // gateway @@ -95,4 +95,4 @@ export { ImplStorageName, ProxyStorageName, ContractFactoryName -} \ No newline at end of file +} diff --git a/contracts/tasks/README.md b/contracts/tasks/README.md index 30a84b60e..1a095e784 100644 --- a/contracts/tasks/README.md +++ b/contracts/tasks/README.md @@ -23,3 +23,16 @@ or `yarn hardhat upgradeProxyWithProxyAdmin --proxyadminaddr 0x5FbDB2315678afecb367f032d93F642f64180aa3 \ --proxyaddr 0x8a791620dd6260079bf849dc5567adc3f2fdc318 --newimpladdr 0x4ed7c70f96b99c776995fb64377f0d4ab3b0e1c1 \ --network l1` + +For the one-time Rollup cutover to Submitter, use the dedicated task instead of +the generic proxy upgrade. It checks that committed batches are fully finalized, +that no challenge or revert request is pending, and then calls +`ProxyAdmin.upgradeAndCall(initialize4)` atomically: + +`yarn hardhat upgradeRollupProxy --proxyadminaddr \ +--rollupproxyaddr --submitterproxyaddr \ +--chainid --network ` + +For a fresh deployment, `batchSubmitterPks` must be a JSON array whose order +matches `batchSubmitterAddresses` in the selected deploy config. The `register` +task owner-authorizes and stakes every configured work or backup submitter. diff --git a/contracts/tasks/deploy.ts b/contracts/tasks/deploy.ts index a7ea6bb6a..ea8ddf23c 100644 --- a/contracts/tasks/deploy.ts +++ b/contracts/tasks/deploy.ts @@ -13,14 +13,14 @@ import { deployContractProxiesConcurrently, deployContractImpls, deployContractImplsConcurrently, + SubmitterInit, MessengerInit, RollupInit, GatewayInit, - StakingInit, AdminTransfer, AdminTransferConcurrently, ContractInit, - StakingRegister, + SubmitterRegister, SequencerInit, } from '../deploy/index' import { ethers } from "ethers"; @@ -97,6 +97,13 @@ task("initialize") return } + console.log('\n---------------------------------- Submitter init ----------------------------------') + err = await SubmitterInit(hre, storagePath, deployer, config) + if (err != '') { + console.log('Submitter init failed, err: ', err) + return + } + console.log('\n---------------------------------- Messenger init ----------------------------------') err = await MessengerInit(hre, storagePath, deployer, config) if (err != '') { @@ -115,12 +122,6 @@ task("initialize") console.log('Rollup init failed, err: ', err) return } - console.log('\n---------------------------------- Staking init ----------------------------------') - err = await StakingInit(hre, storagePath, deployer, config) - if (err != '') { - console.log('Staking init failed, err: ', err) - return - } console.log('\n---------------------------------- Sequencer init ----------------------------------') err = await SequencerInit(hre, storagePath, deployer, config) if (err != '') { @@ -152,25 +153,23 @@ task("initialize") task("fund") .setAction(async (taskArgs, hre) => { - console.log('\n---------------------------------- Fund Staking ----------------------------------') + console.log('\n---------------------------------- Fund Submitters ----------------------------------') const signer = await hre.ethers.getSigners() - console.log(process.env.l2SequencerPks) - let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); - console.log(l2SequencerPkList) - for (let i = 0; i < l2SequencerPkList.length; i++) { - let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) + const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); + for (let i = 0; i < batchSubmitterPkList.length; i++) { + const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) const tx = { - to: sequencer.address, + to: submitter.address, value: ethers.utils.parseEther("100") } - let balance = (await sequencer.getBalance()).toString() + let balance = (await submitter.getBalance()).toString() if (balance.length < 20) { let receipt = await signer[0].sendTransaction(tx) await receipt.wait() } - balance = (await sequencer.getBalance()).toString() - console.log(`${sequencer.address} has balance: ${balance}`) + balance = (await submitter.getBalance()).toString() + console.log(`${submitter.address} has balance: ${balance}`) } }) @@ -181,14 +180,22 @@ task("register") // Initialization parameters const storagePath = taskArgs.storagepath const config = hre.deployConfig - let l2SequencerPkList = JSON.parse(process.env.l2SequencerPks); - for (let i = 0; i < l2SequencerPkList.length; i++) { - let sequencer = new ethers.Wallet(l2SequencerPkList[i], hre.ethers.provider) - console.log(`\n---------------------------------- register sequencer-${i} ----------------------------------`) - console.log(`sequencer-${i}:` + await sequencer.getAddress() + ', Balance: ' + await sequencer.getBalance()) - let err = await StakingRegister(hre, storagePath, sequencer, config.l2SequencerTmKeys[i], config.l2SequencerBlsKeys[i]) + const owner = await hre.ethers.provider.getSigner(); + const batchSubmitterPkList: string[] = JSON.parse(process.env.batchSubmitterPks || "[]"); + const configuredAddresses: string[] = config.batchSubmitterAddresses; + if (batchSubmitterPkList.length !== configuredAddresses.length || batchSubmitterPkList.length === 0) { + throw new Error("batchSubmitterPks must contain one key for every configured work or backup submitter") + } + for (let i = 0; i < batchSubmitterPkList.length; i++) { + const submitter = new ethers.Wallet(batchSubmitterPkList[i], hre.ethers.provider) + if (configuredAddresses[i].toLowerCase() !== submitter.address.toLowerCase()) { + throw new Error(`batch submitter key ${i} does not match configured address`) + } + console.log(`\n---------------------------------- register submitter-${i} ----------------------------------`) + console.log(`submitter-${i}:` + submitter.address + ', Balance: ' + await submitter.getBalance()) + const err = await SubmitterRegister(hre, storagePath, owner, submitter) if (err != '') { - console.log(`Deploy Staking Sequencer-${i} failed, err: `, err) + console.log(`Register Submitter-${i} failed, err: `, err) return } } diff --git a/contracts/tasks/proxy_upgrade.ts b/contracts/tasks/proxy_upgrade.ts index 88b2fb4bb..a10a55967 100644 --- a/contracts/tasks/proxy_upgrade.ts +++ b/contracts/tasks/proxy_upgrade.ts @@ -224,38 +224,58 @@ task("upgradeSystemDictatorImpl") }) /* -Proxy__Rollup - -cast call 0xb7f8bc63bbcad18155201308c8f3540b07f84f5e "layer2ChainId()(uint64)" --rpc-url http://127.0.0.1:9545 -53077 - -cast call 0xb7f8bc63bbcad18155201308c8f3540b07f84f5e "MESSENGER()(address)" --rpc-url http://127.0.0.1:9545 -0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 - -yarn hardhat upgradeRollupImpl --chainid 53077 --l1cdmproxyaddr 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 --network l1 - -yarn hardhat upgradeProxy --proxyaddr 0xb7f8bc63bbcad18155201308c8f3540b07f84f5e --newimpladdr 0x1429859428C0aBc9C2C47C8Ee9FBaf82cFA0F20f --network l1 +One-time Submitter cutover for an existing Rollup. The task deploys the new +implementation, checks the drain gates, and calls ProxyAdmin.upgradeAndCall +with initialize4(address) in the same transaction. */ task("upgradeRollupProxy") .addParam("proxyadminaddr") .addParam("rollupproxyaddr") + .addParam("submitterproxyaddr") .addParam("chainid") .setAction(async (taskArgs, hre) => { + if ( + !hre.ethers.utils.isAddress(taskArgs.proxyadminaddr) || + !hre.ethers.utils.isAddress(taskArgs.rollupproxyaddr) || + !hre.ethers.utils.isAddress(taskArgs.submitterproxyaddr) + ) { + throw new Error("invalid ProxyAdmin, Rollup, or Submitter address") + } + const ProxyAdminFactory = await hre.ethers.getContractFactory('ProxyAdmin') const proxyAdmin = ProxyAdminFactory.attach(taskArgs.proxyadminaddr) - // upgrade - const chainID = taskArgs.chainid const RollupFactory = await hre.ethers.getContractFactory("Rollup"); - const rollupNewImpl = await RollupFactory.deploy(chainID); + const rollup = await hre.ethers.getContractAt("Rollup", taskArgs.rollupproxyaddr) + const lastCommitted = await rollup.lastCommittedBatchIndex() + const lastFinalized = await rollup.lastFinalizedBatchIndex() + if (!lastCommitted.eq(lastFinalized)) { + throw new Error(`Rollup is not drained: committed=${lastCommitted} finalized=${lastFinalized}`) + } + if (await rollup.inChallenge()) { + throw new Error("Rollup has a challenge in progress") + } + if (!(await rollup.revertReqIndex()).isZero()) { + throw new Error("Rollup has a pending revert request") + } + + const rollupNewImpl = await RollupFactory.deploy(taskArgs.chainid); await rollupNewImpl.deployed() console.log("new rollupNewImpl contract address: ", rollupNewImpl.address) - if (!hre.ethers.utils.isAddress(taskArgs.rollupproxyaddr) || !hre.ethers.utils.isAddress(rollupNewImpl.address)) { - console.log(`not address ${taskArgs.rollupproxyaddr} ${rollupNewImpl.address}`) - return - } - const res = await proxyAdmin.upgrade(taskArgs.rollupproxyaddr, rollupNewImpl.address) + + const initializer = RollupFactory.interface.encodeFunctionData("initialize4", [ + taskArgs.submitterproxyaddr, + ]) + const res = await proxyAdmin.upgradeAndCall( + taskArgs.rollupproxyaddr, + rollupNewImpl.address, + initializer + ) const rec = await res.wait() - console.log(`upgrade rollup ${rec.status === 1}`) + const configuredSubmitter = await rollup.submitterContract() + if (configuredSubmitter.toLowerCase() !== taskArgs.submitterproxyaddr.toLowerCase()) { + throw new Error("Rollup Submitter cutover verification failed") + } + console.log(`upgrade Rollup and initialize Submitter dependency ${rec.status === 1}`) }) /* @@ -314,4 +334,4 @@ task("gasOracleProxy-upgrade") let res = await proxyAdmin.upgrade(predeploys.GasPriceOracle, gasOracleProxyNewImpl.address) let rec = await res.wait() console.log(`upgrade gasOracleProxy ${rec.status == 1 ? "success" : "failed"}`) - }) \ No newline at end of file + }) diff --git a/contracts/tasks/staking_upgrade.ts b/contracts/tasks/staking_upgrade.ts deleted file mode 100644 index 9a237e62d..000000000 --- a/contracts/tasks/staking_upgrade.ts +++ /dev/null @@ -1,901 +0,0 @@ -import "@nomiclabs/hardhat-web3" -import "@nomiclabs/hardhat-ethers" -import "@nomiclabs/hardhat-waffle" - -import fs from "fs"; -import assert from "assert" -import { task } from "hardhat/config" -import { ethers } from "ethers" -import { assertContractVariable, getContractAddressByName, awaitCondition, storage } from "../src/deploy-utils" -import { ImplStorageName, ProxyStorageName, ContractFactoryName } from "../src/types" -import { predeploys } from "../src" -import { hexlify } from "ethers/lib/utils"; - -task("rollup-deploy-init") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - const config = hre.deployConfig - const chainId = config.l2ChainID - const deployer = hre.ethers.provider.getSigner() - - const ProxyFactoryName = ContractFactoryName.DefaultProxy - const IProxyFactoryName = ContractFactoryName.DefaultProxyInterface - const RollupFactoryName = ContractFactoryName.Rollup - const RollupImplStorageName = ImplStorageName.RollupStorageName - const RollupProxyStorageName = ProxyStorageName.RollupProxyStorageName - const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) - - const RollupFactory = await hre.ethers.getContractFactory(RollupFactoryName) - const rollupNewImpl = await RollupFactory.deploy(chainId) - await rollupNewImpl.deployed() - let blockNumber = await hre.ethers.provider.getBlockNumber() - let err = await storage( - newPath, - RollupImplStorageName, - rollupNewImpl.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - console.log(`Rollup new impl deploy at ${rollupNewImpl.address}`) - - // Proxy deploy - const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) - // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin - const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") - await proxy.deployed() - blockNumber = await hre.ethers.provider.getBlockNumber() - err = await storage(newPath, RollupProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) - if (err != "") { - return err - } - console.log(`Rollup proxy deploy at ${proxy.address}`) - - // ------------------ deploy MultipleVersionRollupVerifier ----------------- - { - // deploy ZkEvmVerifierV1 - const ZkEvmVerifierV1ContractFactoryName = ContractFactoryName.ZkEvmVerifierV1 - const ZkEvmVerifierV1ImplStorageName = ImplStorageName.ZkEvmVerifierV1StorageName - const Factory = await hre.ethers.getContractFactory(ZkEvmVerifierV1ContractFactoryName) - const contract = await Factory.deploy(config.programVkey) - await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - let blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - let err = await storage(newPath, ZkEvmVerifierV1ImplStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) - if (err != '') { - return err - } - - - // deploy MultipleVersionRollupVerifier - const ZkEvmVerifierV1Address = getContractAddressByName( - newPath, - ImplStorageName.ZkEvmVerifierV1StorageName - ) - const MultipleVersionRollupVerifierFactoryName = ContractFactoryName.MultipleVersionRollupVerifier - const MultipleVersionRollupVerifierImplStorageName = - ImplStorageName.MultipleVersionRollupVerifierStorageName - console.log("Deploy the MultipleVersionRollupVerifier ...") - const MultipleVersionRollupVerifierFactory = await hre.ethers.getContractFactory( - MultipleVersionRollupVerifierFactoryName - ) - const version = [0] - const verifiers = [ZkEvmVerifierV1Address] - const MultipleVersionRollupVerifierContract = await MultipleVersionRollupVerifierFactory.deploy( - version, - verifiers - ) - await MultipleVersionRollupVerifierContract.deployed() - await MultipleVersionRollupVerifierContract.initialize(proxy.address) - console.log( - "%s=%s ; TX_HASH: %s", - MultipleVersionRollupVerifierImplStorageName, - MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), - MultipleVersionRollupVerifierContract.deployTransaction.hash - ) - blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - err = await storage( - newPath, - MultipleVersionRollupVerifierImplStorageName, - MultipleVersionRollupVerifierContract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // ------------------ rollup initialize ----------------- - { - const IRollupProxy = await hre.ethers.getContractAt(IProxyFactoryName, proxy.address, deployer) - console.log("Upgrading the Rollup proxy...") - const finalizationPeriodSeconds: number = config.finalizationPeriodSeconds - const proofWindow: number = config.rollupProofWindow - - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1StakingProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1StakingProxyStorageName - ) - const MultipleVersionRollupVerifierContractAddress = getContractAddressByName( - newPath, - ImplStorageName.MultipleVersionRollupVerifierStorageName - ) - if ( - !ethers.utils.isAddress(L1MessageQueueWithGasPriceOracleProxyAddress) || - !ethers.utils.isAddress(MultipleVersionRollupVerifierContractAddress) || - !ethers.utils.isAddress(L1StakingProxyAddress) - ) { - console.error("please check your address") - return "" - } - - // Upgrade and initialize the proxy. - await IRollupProxy.upgradeToAndCall( - rollupNewImpl.address, - RollupFactory.interface.encodeFunctionData("initialize", [ - L1StakingProxyAddress, - L1MessageQueueWithGasPriceOracleProxyAddress, - MultipleVersionRollupVerifierContractAddress, - finalizationPeriodSeconds, - proofWindow, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IRollupProxy.implementation()).toLocaleLowerCase() === - rollupNewImpl.address.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - // params check - const contractTmp = new ethers.Contract(proxy.address, RollupFactory.interface, deployer) - await assertContractVariable(contractTmp, "l1StakingContract", L1StakingProxyAddress) - await assertContractVariable(contractTmp, "messageQueue", L1MessageQueueWithGasPriceOracleProxyAddress) - await assertContractVariable(contractTmp, "verifier", MultipleVersionRollupVerifierContractAddress) - await assertContractVariable(contractTmp, "finalizationPeriodSeconds", finalizationPeriodSeconds) - await assertContractVariable(contractTmp, "proofWindow", proofWindow) - await assertContractVariable(contractTmp, "owner", await deployer.getAddress()) - - // Wait for the transaction to execute properly. - console.log(`RollupProxy upgrade success, Rollup address at ${proxy.address}`) - } - - // ------------------ Admin transfer ----------------- - { - const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() - const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - proxy.address, - deployer - ) - { - const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() - const admin = (await IProxyContract.admin()).toLocaleLowerCase() - if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { - return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` - } - if (admin !== deployerAddr) { - return `Proxy admin address ${admin} should deployer address ${deployerAddr}` - } - } - console.log(`change rollup admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) - const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) - await res.wait() - await assertContractVariable( - IProxyContract, - "admin", - ProxyAdminImplAddr, - ProxyAdminImplAddr // caller - ) - console.log(`admin transfer successful`) - } - }) - -task("rollup-import-genesis-batch") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const newPath = taskArgs.newpath - const config = hre.deployConfig - const deployer = hre.ethers.provider.getSigner() - // ------------------ rollup import genesis batch ----------------- - { - const NewRollupContractAddr = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const Rollup = await hre.ethers.getContractAt(ContractFactoryName.Rollup, NewRollupContractAddr, deployer) - // import genesis batch - const batchHeader: string = config.batchHeader - - // submitter and challenger - const submitter: string = config.rollupProposer - const challenger: string = config.rollupChallenger - if (!ethers.utils.isAddress(submitter) || !ethers.utils.isAddress(challenger)) { - console.error("please check your address") - return "" - } - let res = await Rollup.importGenesisBatch(batchHeader) - let rec = await res.wait() - console.log( - `importGenesisBatch(%s) ${rec.status == 1 ? "success" : "failed"}`, - batchHeader, - ) - res = await Rollup.addChallenger(challenger) - rec = await res.wait() - console.log(`addChallenger(%s) ${rec.status == 1 ? "success" : "failed"}`, challenger) - const batch = await Rollup.batchBaseStore(0) - assert(batch.batchHash.toLowerCase() != "", `[FATAL] import genesis batch failed`) - } - }) - -task("l1mq-upgrade") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1MessageQueueWithGasPriceOracleFactoryName = ContractFactoryName.L1MessageQueueWithGasPriceOracle - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - const EnforcedTxGatewayAddress = getContractAddressByName( - storagePath, - ProxyStorageName.EnforcedTxGatewayProxyStorageName - ) - const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - - // deploy L1MessageQueueWithGasPriceOracle impl - { - const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const Factory = await hre.ethers.getContractFactory(L1MessageQueueWithGasPriceOracleFactoryName) - const contract = await Factory.deploy( - L1CrossDomainMessengerProxyAddress, - NewRollupProxyAddress, - EnforcedTxGatewayAddress - ) - await contract.deployed() - console.log( - "%s=%s ; TX_HASH: %s", - ImplStorageName.L1MessageQueueWithGasPriceOracle, - contract.address.toLocaleLowerCase(), - contract.deployTransaction.hash - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage( - newPath, - ImplStorageName.L1MessageQueueWithGasPriceOracle, - contract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // L1MessageQueueWithGasPriceOracle proxy upgrade - { - const L1MessageQueueWithGasPriceOracleNewImplAddress = getContractAddressByName( - newPath, - ImplStorageName.L1MessageQueueWithGasPriceOracle - ) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) - const res = await proxyAdmin.upgrade( - L1MessageQueueWithGasPriceOracleProxyAddress, - L1MessageQueueWithGasPriceOracleNewImplAddress - ) - const rec = await res.wait() - console.log(`upgrade l1MessageQueueWithGasPriceOracle.rollup ${rec.status === 1}`) - } - }) - -task("l1cdm-upgrade") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1CrossDomainMessengerFactoryName = ContractFactoryName.L1CrossDomainMessenger - const L1CrossDomainMessengerImplStorageName = ImplStorageName.L1CrossDomainMessengerStorageName - const ProxyAdminAddress = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - - // deploy l1CrossDomainMessenger impl - { - const Factory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) - const contract = await Factory.deploy() - await contract.deployed() - console.log( - "%s=%s ; TX_HASH: %s", - L1CrossDomainMessengerImplStorageName, - contract.address.toLocaleLowerCase(), - contract.deployTransaction.hash - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage( - newPath, - L1CrossDomainMessengerImplStorageName, - contract.address.toLocaleLowerCase(), - blockNumber || 0 - ) - if (err != "") { - return err - } - } - - // l1CrossDomainMessenger proxy upgrade - { - const L1CrossDomainMessengerNewImplAddress = getContractAddressByName( - newPath, - L1CrossDomainMessengerImplStorageName - ) - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(ProxyAdminAddress) - const res = await proxyAdmin.upgrade( - L1CrossDomainMessengerProxyAddress, - L1CrossDomainMessengerNewImplAddress - ) - const rec = await res.wait() - console.log(`upgrade l1CrossDomainMessenger ${rec.status === 1}`) - } - - // l1CrossDomainMessenger update Rollup address - { - const NewRollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const L1CDMFactory = await hre.ethers.getContractFactory(L1CrossDomainMessengerFactoryName) - const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) - const res = await l1CrossDomainMessenger.updateRollup(NewRollupProxyAddress) - const rec = await res.wait() - console.log(`update l1CrossDomainMessenger.rollup ${rec.status === 1}`) - } - }) - - -task("l1staking-deploy-init") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - // deploy config - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - const config = hre.deployConfig - const deployer = hre.ethers.provider.getSigner() - - const ProxyFactoryName = ContractFactoryName.DefaultProxy - const L1StakingProxyStorageName = ProxyStorageName.L1StakingProxyStorageName - const WhitelistImplAddress = getContractAddressByName(storagePath, ImplStorageName.Whitelist) - const EmptyContractAddr = getContractAddressByName(storagePath, ImplStorageName.EmptyContract) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName(storagePath, ProxyStorageName.L1CrossDomainMessengerProxyStorageName) - - // deploy L1Staking proxy - { - const ProxyFactory = await hre.ethers.getContractFactory(ProxyFactoryName) - // TransparentUpgradeableProxy deploy with emptyContract as impl, deployer as admin - const proxy = await ProxyFactory.deploy(EmptyContractAddr, await deployer.getAddress(), "0x") - await proxy.deployed() - const blockNumber = await hre.ethers.provider.getBlockNumber() - const err = await storage(newPath, L1StakingProxyStorageName, proxy.address.toLocaleLowerCase(), blockNumber || 0) - if (err != "") { - console.log(`deploy L1Staking proxy failed ${err}`) - return err - } - console.log(`L1Staking proxy deploy at ${proxy.address}`) - } - - // deploy impl - { - const Factory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - const contract = await Factory.deploy(L1CrossDomainMessengerProxyAddress) - await contract.deployed() - console.log("%s=%s ; TX_HASH: %s", ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), contract.deployTransaction.hash); - await assertContractVariable( - contract, - 'MESSENGER', - L1CrossDomainMessengerProxyAddress - ) - await assertContractVariable( - contract, - 'OTHER_STAKING', - predeploys.L2Staking.toLowerCase() - ) - const blockNumber = await hre.ethers.provider.getBlockNumber() - console.log("BLOCK_NUMBER: %s", blockNumber) - const err = await storage(newPath, ImplStorageName.L1StakingStorageName, contract.address.toLocaleLowerCase(), blockNumber || 0) - if (err != '') { - console.log(`deploy L1Staking implemention failed ${err}`) - return err - } - } - - // upgrade - { - const RollupProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - // Staking config - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const L1StakingImplAddress = getContractAddressByName(newPath, ImplStorageName.L1StakingStorageName) - const L1StakingFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1Staking) - const IL1StakingProxy = await hre.ethers.getContractAt(ContractFactoryName.DefaultProxyInterface, L1StakingProxyAddress, deployer) - - console.log('Upgrading the Staking proxy...') - const admin: string = config.contractAdmin - const stakingChallengerRewardPercentage: number = config.stakingChallengerRewardPercentage - const limit: number = config.stakingMinDeposit - const lock: number = config.stakingLockNumber - const gasLimitAdd: number = config.stakingCrossChainGaslimitAdd - const gasLimitRemove: number = config.stakingCrossChainGaslimitRemove - - if (!ethers.utils.isAddress(admin) - || lock <= 0 - || limit <= 0 - || gasLimitAdd <= 0 - || gasLimitRemove <= 0 - || stakingChallengerRewardPercentage > 100 - || stakingChallengerRewardPercentage <= 0 - ) { - console.error('please check your address') - return '' - } - - // Upgrade and initialize the proxy. - await IL1StakingProxy.upgradeToAndCall( - L1StakingImplAddress, - L1StakingFactory.interface.encodeFunctionData('initialize', [ - RollupProxyAddress, - hre.ethers.utils.parseEther(limit.toString()), - hre.ethers.utils.parseEther(lock.toString()), - stakingChallengerRewardPercentage, - gasLimitAdd, - gasLimitRemove, - ]) - ) - - await awaitCondition( - async () => { - return ( - (await IL1StakingProxy.implementation()).toLocaleLowerCase() === L1StakingImplAddress.toLocaleLowerCase() - ) - }, - 3000, - 1000 - ) - - const contractTmp = new ethers.Contract( - L1StakingProxyAddress, - L1StakingFactory.interface, - deployer, - ) - - await assertContractVariable( - contractTmp, - 'rollupContract', - RollupProxyAddress - ) - await assertContractVariable( - contractTmp, - 'rewardPercentage', - stakingChallengerRewardPercentage - ) - await assertContractVariable( - contractTmp, - 'stakingValue', - hre.ethers.utils.parseEther(limit.toString()) - ) - await assertContractVariable( - contractTmp, - 'withdrawalLockBlocks', - hre.ethers.utils.parseEther(lock.toString()) - ) - await assertContractVariable( - contractTmp, - 'gasLimitAddStaker', - gasLimitAdd - ) - await assertContractVariable( - contractTmp, - 'gasLimitRemoveStakers', - gasLimitRemove - ) - await assertContractVariable( - contractTmp, - 'owner', - await deployer.getAddress(), - ) - // Wait for the transaction to execute properly. - console.log('StakingProxy upgrade success') - } - - // ------------------ Admin transfer ----------------- - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const deployerAddr = (await deployer.getAddress()).toLocaleLowerCase() - const ProxyAdminImplAddr = getContractAddressByName(storagePath, ImplStorageName.ProxyAdmin) - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - L1StakingProxyAddress, - deployer - ) - { - const implAddr = (await IProxyContract.implementation()).toLocaleLowerCase() - const admin = (await IProxyContract.admin()).toLocaleLowerCase() - if (implAddr === EmptyContractAddr.toLocaleLowerCase()) { - return `Proxy implementation address ${implAddr} should not be empty contract address ${EmptyContractAddr}` - } - if (admin !== deployerAddr) { - return `Proxy admin address ${admin} should deployer address ${deployerAddr}` - } - } - console.log(`change L1Staking admin transfer from ${deployerAddr} to ProxyAdmin ${ProxyAdminImplAddr}`) - const res = await IProxyContract.changeAdmin(ProxyAdminImplAddr) - await res.wait() - await assertContractVariable( - IProxyContract, - "admin", - ProxyAdminImplAddr, - ProxyAdminImplAddr // caller - ) - console.log(`admin transfer successful`) - } - - // set L1Staking address to gasPriceOracle whitelist - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const WhitelistCheckerImpl = await hre.ethers.getContractAt(ContractFactoryName.Whitelist, WhitelistImplAddress, deployer) - let addList = [L1StakingProxyAddress] - const res = await WhitelistCheckerImpl.updateWhitelistStatus(addList, true) - await res.wait() - for (let i = 0; i < addList.length; i++) { - let res = await WhitelistCheckerImpl.isSenderAllowed(addList[i]) - if (res != true) { - console.error('whitelist check failed') - return '' - } - } - console.log(`add ${addList} to whitelist success`) - } - - // set staker whitelist - { - const L1StakingProxyAddress = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - const L1Staking = await hre.ethers.getContractAt(ContractFactoryName.L1Staking, L1StakingProxyAddress, deployer) - const whiteListAdd = config.l2SequencerAddresses - // set sequencer to white list - await L1Staking.updateWhitelist(whiteListAdd, []) - for (let i = 0; i < config.l2SequencerAddresses.length; i++) { - // Wait for the transaction to execute properly. - await awaitCondition( - async () => { - return ( - await L1Staking.whitelist(config.l2SequencerAddresses[i]) === true - ) - }, - 3000, - 1000 - ) - console.log(`address ${config.l2SequencerAddresses[i]} is in white list`) - } - } - }) - -task("check-params") - .addParam("storagepath") - .addParam("newpath") - .setAction(async (taskArgs, hre) => { - const storagePath = taskArgs.storagepath - const newPath = taskArgs.newpath - - const L1MessageQueueWithGasPriceOracleProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1MessageQueueWithGasPriceOracleProxyStorageName - ) - const L1CrossDomainMessengerProxyAddress = getContractAddressByName( - storagePath, - ProxyStorageName.L1CrossDomainMessengerProxyStorageName - ) - const RollupNewProxyAddress = getContractAddressByName(newPath, ProxyStorageName.RollupProxyStorageName) - - const L1CDMFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1CrossDomainMessenger) - const l1CrossDomainMessenger = L1CDMFactory.attach(L1CrossDomainMessengerProxyAddress) - let res = await l1CrossDomainMessenger.rollup() - assert( - RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), - `l1CrossDomainMessenger assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` - ) - - const L1MQFactory = await hre.ethers.getContractFactory(ContractFactoryName.L1MessageQueueWithGasPriceOracle) - const l1mq = L1MQFactory.attach(L1MessageQueueWithGasPriceOracleProxyAddress) - res = await l1mq.ROLLUP_CONTRACT() - assert( - RollupNewProxyAddress.toLowerCase() === res.toLowerCase(), - `l1mq assert rollup address assert failed, expect ${RollupNewProxyAddress}, actual ${res}` - ) - console.log("Check new rollup address success") - }) - -// test command -// rm -rf ./deployFile.json && \ -// yarn hardhat deploy --storagepath ./deployFile.json --network l1 && \ -// yarn hardhat initialize --storagepath ./deployFile.json --network l1 && \ -// yarn hardhat fund --network l1 && \ -// yarn hardhat register --storagepath ./deployFile.json --network l1 && \ -// rm -rf ./newFile.json && \ -// yarn hardhat rollup-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1mq-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1cdm-upgrade --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat check-params --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat l1staking-deploy-init --storagepath ./deployFile.json --newpath ./newFile.json --network l1 && \ -// yarn hardhat register --storagepath ./newFile.json --network l1 - -// immutable upgrade test -task("impl-test") - .setAction(async (taskArgs, hre) => { - const deployer = hre.ethers.provider.getSigner() - const V1Factory = await hre.ethers.getContractFactory("TestUpgradeV1") - const V2Factory = await hre.ethers.getContractFactory("TestUpgradeV2") - - const v1Impl = await V1Factory.deploy() - await v1Impl.deployed() - const v2Impl = await V2Factory.deploy() - await v2Impl.deployed() - console.log(`V1 and V2 impl deploy success and v1: ${v1Impl.address} , v2: ${v2Impl.address}`) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = await ProxyAdminFactory.deploy() - await proxyAdmin.deployed() - const ProxyFactory = await hre.ethers.getContractFactory(ContractFactoryName.DefaultProxy) - const proxy = await ProxyFactory.deploy(v1Impl.address, await deployer.getAddress(), "0x") - await proxy.deployed() - const IProxyContract = await hre.ethers.getContractAt( - ContractFactoryName.DefaultProxyInterface, - proxy.address, - deployer - ) - - // transfer owner to proxy admin - { - const res = await IProxyContract.changeAdmin(proxyAdmin.address) - const rec = await res.wait() - console.log(`proxy admin change to proxy admin ${rec.status === 1}`) - } - - const consoleParams = async (factory) => { - const contractTmp = new ethers.Contract( - proxy.address, - factory.interface, - hre.ethers.provider, - ) - let va = await contractTmp.va({ from: hre.ethers.constants.AddressZero }) - let vb = await contractTmp.vb({ from: hre.ethers.constants.AddressZero }) - let vc = await contractTmp.vc({ from: hre.ethers.constants.AddressZero }) - let version = await contractTmp.version({ from: hre.ethers.constants.AddressZero }) - console.log(`va ${va} ; vb ${vb} ; vc ${vc} ; version ${version}`) - } - let contract = new ethers.Contract( - proxy.address, - V1Factory.interface, - deployer, - ) - let res = await contract.setVersion(100) - let rec = await res.wait() - console.log(`update version to 100 ${rec.status === 1}`) - await consoleParams(V1Factory) - - // upgrade - { - const res = await proxyAdmin.upgrade(proxy.address, v2Impl.address) - const rec = await res.wait() - console.log(`upgrade to v2 impl ${rec.status === 1}`) - } - contract = new ethers.Contract( - proxy.address, - V2Factory.interface, - deployer, - ) - res = await contract.setVersion(101) - rec = await res.wait() - console.log(`update version to 101 ${rec.status === 1}`) - res = await contract.setOtherVersion(99) - rec = await res.wait() - console.log(`update otherVersion to 99 ${rec.status === 1}`) - console.log("upgrade success") - await consoleParams(V2Factory) - }) - -// ------------------------------------ L2 Upgrade ------------------------------------ -task("gov-upgrade") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const GovFactory = await hre.ethers.getContractFactory("Gov") - const newGovImpl = await GovFactory.deploy() - await newGovImpl.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Gov, - newGovImpl.address, - GovFactory.interface.encodeFunctionData('initializeV2', [ - l2Config.govVotingDuration, - l2Config.govBatchBlockInterval, - l2Config.govBatchMaxBytes, - l2Config.govBatchTimeout, - l2Config.govBatchMaxChunks, - l2Config.govRollupEpoch, - ]) - ) - const rec = await res.wait() - console.log(`gov upgrade ${rec.status === 1}`) - }) - -task("distribute-deploy") - .setAction(async (taskArgs, hre) => { - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const DistributeFactory = await hre.ethers.getContractFactory("Distribute") - const distribute = await DistributeFactory.deploy() - await distribute.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Distribute, - distribute.address, - DistributeFactory.interface.encodeFunctionData('initialize', []) - ) - const rec = await res.wait() - console.log(`distribute upgrade ${rec.status === 1}, new impl ${distribute.address}`) - }) - -task("morph-token-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const MorphTokenFactory = await hre.ethers.getContractFactory("MorphToken") - const morphToken = await MorphTokenFactory.deploy() - await morphToken.deployed() - - const res = await proxyAdmin.upgradeAndCall( - predeploys.MorphToken, - morphToken.address, - MorphTokenFactory.interface.encodeFunctionData('initialize', [ - l2Config.morphTokenName, - l2Config.morphTokenSymbol, - l2Config.morphTokenOwner, - hre.ethers.utils.parseEther(l2Config.morphTokenInitialSupply.toString()), - l2Config.morphTokenDailyInflationRate, - ]) - ) - const rec = await res.wait() - console.log(`morphToken upgrade ${rec.status === 1}, new impl ${morphToken.address}`) - }) - -task("sequencer-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const SequencerFactory = await hre.ethers.getContractFactory("Sequencer") - const sequencer = await SequencerFactory.deploy() - await sequencer.deployed() - - // l2Config - let addresses = [] - for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { - addresses.push(l2Config.l2StakingAddresses[i]) - } - const res = await proxyAdmin.upgradeAndCall( - predeploys.Sequencer, - sequencer.address, - SequencerFactory.interface.encodeFunctionData( - 'initialize', - [addresses]) - ) - const rec = await res.wait() - console.log(`sequencer upgrade ${rec.status === 1}, new impl ${sequencer.address}`) - }) - -task("record-deploy") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const RecordFactory = await hre.ethers.getContractFactory("Record") - const record = await RecordFactory.deploy() - await record.deployed() - const res = await proxyAdmin.upgradeAndCall( - predeploys.Record, - record.address, - RecordFactory.interface.encodeFunctionData('initialize', [ - l2Config.recordOracleAddress, - l2Config.recordNextBatchSubmissionIndex, - ]) - ) - const rec = await res.wait() - console.log(`Record upgrade ${rec.status === 1}, new impl ${record.address}`) - }) - -task("l2-staking-deploy") - .addParam("newpath") - .addParam("l2config") - .setAction(async (taskArgs, hre) => { - const newPath = taskArgs.newpath - const data = fs.readFileSync(taskArgs.l2config); - // @ts-ignore - const l2Config = JSON.parse(data); - const L1StakingProxyAddr = getContractAddressByName(newPath, ProxyStorageName.L1StakingProxyStorageName) - - const ProxyAdminFactory = await hre.ethers.getContractFactory(ContractFactoryName.ProxyAdmin) - const proxyAdmin = ProxyAdminFactory.attach(predeploys.ProxyAdmin) - - const L2StakingFactory = await hre.ethers.getContractFactory("L2Staking") - const staking = await L2StakingFactory.deploy(L1StakingProxyAddr) - await staking.deployed() - - let infos = [] - for (let i = 0; i < l2Config.l2StakingAddresses.length; i++) { - let info = { - addr: l2Config.l2StakingAddresses[i], - tmKey: l2Config.l2StakingTmKeys[i], - blsKey: l2Config.l2StakingBlsKeys[i], - } - infos.push(info) - } - const res = await proxyAdmin.upgradeAndCall( - predeploys.L2Staking, - staking.address, - L2StakingFactory.interface.encodeFunctionData('initialize', [ - l2Config.l2StakingSequencerMaxSize, - l2Config.l2StakingUnDelegatedLockEpochs, - l2Config.l2StakingRewardStartTime, - infos, - ]) - ) - const rec = await res.wait() - console.log(`L2Staking upgrade ${rec.status === 1}, new impl ${staking.address}`) - }) \ No newline at end of file From 3e4b88515a220fb8c569899672e96e54cc21ba73 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:03:05 +0800 Subject: [PATCH 24/38] feat(batch): seal zero-field submitter batches --- common/batch/batch_cache.go | 87 +++------ .../batch/batch_cache_genesis_header_test.go | 6 +- common/batch/batch_cache_test.go | 6 +- common/batch/batch_query.go | 166 ++++-------------- common/batch/batch_query_test.go | 108 ++++++++++++ common/batch/batch_restart_test.go | 57 ++---- common/batch/batch_storage_test.go | 2 +- common/batch/commit_test.go | 19 +- common/batch/interfaces.go | 13 +- common/batch/l2_gov.go | 51 +----- 10 files changed, 207 insertions(+), 308 deletions(-) create mode 100644 common/batch/batch_query_test.go diff --git a/common/batch/batch_cache.go b/common/batch/batch_cache.go index 74b987a70..933d678dc 100644 --- a/common/batch/batch_cache.go +++ b/common/batch/batch_cache.go @@ -94,6 +94,8 @@ func NewBatchCache( isBatchUpgraded func(uint64) bool, isBatchV2Upgraded func(uint64) bool, maxBlobCount int, + blockInterval uint64, + batchTimeOut uint64, l1Client L1HeaderClient, l2Clients L2MultiClient, rollupContract RollupBatchReader, @@ -143,15 +145,13 @@ func NewBatchCache( rollupContract: rollupContract, l2Gov: l2Gov, batchStorage: NewBatchStorage(ldb), + blockInterval: blockInterval, + batchTimeOut: batchTimeOut, maxBlobCount: maxBlobCount, } } func (bc *BatchCache) Init() error { - err := bc.updateBatchConfigFromGov() - if err != nil { - return err - } ci, fi, err := bc.getBatchStatusFromContract() if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) @@ -227,10 +227,6 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { if bc.isInitialized() { return nil } - err := bc.updateBatchConfigFromGov() - if err != nil { - return err - } ci, fi, err := bc.getBatchStatusFromContract() if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) @@ -375,21 +371,6 @@ func (bc *BatchCache) LatestBatchIndex() (uint64, error) { return bc.parentBatchHeader.BatchIndex() } -func (bc *BatchCache) updateBatchConfigFromGov() error { - interval, err := bc.l2Gov.BatchBlockInterval(nil) - if err != nil { - return err - } - timeout, err := bc.l2Gov.BatchTimeout(nil) - if err != nil { - return err - } - bc.batchTimeOut = timeout.Uint64() - bc.blockInterval = interval.Uint64() - log.Info("Update batch config success", "interval", interval.Uint64(), "timeout", timeout.Uint64()) - return nil -} - func (bc *BatchCache) checkBatchHashCorrect(batchIndex *big.Int, batchHash common.Hash) (bool, error) { commitBatchHash, err := bc.rollupContract.CommittedBatches(nil, batchIndex) if err != nil { @@ -666,7 +647,6 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // SealBatch seals the currently accumulated batch, generates batch header and stores to sealedBatches // Parameters: -// - sequencerSetVerifyHash: sequencer set verification hash (obtained from L1 contract) // - blockTimestamp: current block timestamp (used to determine batch version) // // Returns: @@ -680,7 +660,7 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // replayCommittedBatchIndex, when non-nil, is the rollup batch index being re-sealed while syncing // from L1 (InitAndSyncFromRollup). After V2 multi-blob, blob capacity is capped at replayProtocolMaxBlobs // (6), not max_blob_count, without querying L1 CommitBatch logs. -func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { +func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { bc.mu.Lock() defer bc.mu.Unlock() @@ -722,7 +702,7 @@ func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, rep ) // Create batch header - batchHeader := bc.createBatchHeader(batchDataHash, sidecar, crypto.Keccak256Hash(sequencerSets), blockTimestamp) + batchHeader := bc.createBatchHeader(batchDataHash, sidecar, blockTimestamp) // Calculate batch hash batchHash, err := batchHeader.Hash() @@ -755,26 +735,21 @@ func (bc *BatchCache) SealBatch(sequencerSets []byte, blockTimestamp uint64, rep } blockContexts := hexutil.Bytes(blockContextsData) - // Convert sequencerSetVerifyHash to bytes - currentSequencerSetBytes := hexutil.Bytes(sequencerSets) - // Get L1 message count from batch data numL1Messages := bc.batchData.l1TxNum // Store sealed batch information as RPCRollupBatch sealedBatch := ð.RPCRollupBatch{ - Version: uint(version), - Hash: batchHash, - ParentBatchHeader: parentBatchHeaderBytes, - BlockContexts: blockContexts, - CurrentSequencerSetBytes: currentSequencerSetBytes, - PrevStateRoot: bc.prevStateRoot, - PostStateRoot: bc.postStateRoot, - WithdrawRoot: bc.withdrawRoot, - LastBlockNumber: bc.lastPackedBlockHeight, - NumL1Messages: numL1Messages, - Sidecar: *sidecar, - Signatures: []eth.RPCBatchSignature{}, + Version: uint(version), + Hash: batchHash, + ParentBatchHeader: parentBatchHeaderBytes, + BlockContexts: blockContexts, + PrevStateRoot: bc.prevStateRoot, + PostStateRoot: bc.postStateRoot, + WithdrawRoot: bc.withdrawRoot, + LastBlockNumber: bc.lastPackedBlockHeight, + NumL1Messages: numL1Messages, + Sidecar: *sidecar, } bc.sealedBatches[batchIndex] = sealedBatch // Store batch header copy @@ -915,7 +890,7 @@ func (bc *BatchCache) handleBatchSealing(blockTimestamp uint64, sealBlobCap int, } // createBatchHeader creates BatchHeader -func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, sequencerSetVerifyHash common.Hash, blockTimestamp uint64) BatchHeaderBytes { +func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, blockTimestamp uint64) BatchHeaderBytes { blobHashes := []common.Hash{blob.EmptyVersionedHash} if sidecar != nil && len(sidecar.Blobs) > 0 { blobHashes = sidecar.BlobHashes() @@ -942,7 +917,7 @@ func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes. PrevStateRoot: bc.prevStateRoot, PostStateRoot: bc.postStateRoot, WithdrawalRoot: bc.withdrawRoot, - SequencerSetVerifyHash: sequencerSetVerifyHash, + SequencerSetVerifyHash: common.Hash{}, ParentBatchHash: parentBatchHash, } @@ -1114,10 +1089,6 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( } } - sequencerSet, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return nil, fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) - } // Get the last block's timestamp for packing lastBlock, err := bc.l2Clients.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) if err != nil { @@ -1126,7 +1097,7 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(sequencerSet, blockTimestamp, replayCommittedBatchIndex) + batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, replayCommittedBatchIndex) if err != nil { return nil, fmt.Errorf("failed to seal batch: %w", err) } @@ -1180,7 +1151,7 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract + // This ensures batch is sealed before exceeding the configured maximum timeout. timeout := false if bc.batchTimeOut > 0 { elapsedTime := nowBlockTime - startBlockTime @@ -1195,7 +1166,7 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { // check ensures batch is sealed before exceeding the maximum timeout if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum-1, "exceeded", exceeded, "timeout", timeout) - batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(callOpts, ci) + batchHash, reachedExpectedSize, batchIndex, err := bc.SealBatchAndCheck(ci) if err != nil { return err } @@ -1225,18 +1196,14 @@ func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { return nil } -func (bc *BatchCache) SealBatchAndCheck(callOpts *bind.CallOpts, ci *big.Int) (common.Hash, bool, uint64, error) { - sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return common.Hash{}, false, 0, err - } +func (bc *BatchCache) SealBatchAndCheck(ci *big.Int) (common.Hash, bool, uint64, error) { lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) + batchIndex, batchHeaderBytes, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, nil) if err != nil { return common.Hash{}, false, 0, fmt.Errorf("failed to seal batch: %w", err) } @@ -1442,7 +1409,7 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { bc.logBatchPackingProgress(startBlockNum, blockNum, startBlockTime, nowBlockTime, &progressState) // Check timeout: if elapsed time >= batchTimeOut, must seal batch immediately - // This ensures batch is sealed before exceeding the maximum timeout configured in gov contract + // This ensures batch is sealed before exceeding the configured maximum timeout. timeout := false if bc.batchTimeOut > 0 { elapsedTime := nowBlockTime - startBlockTime @@ -1457,16 +1424,12 @@ func (bc *BatchCache) AssembleCurrentBatchHeader() error { // check ensures batch is sealed before exceeding the maximum timeout if exceeded || (bc.blockInterval > 0 && (blockNum-startBlockNum+1) == bc.blockInterval) || timeout { log.Info("block exceeds limit", "start", startBlockNum, "to", blockNum, "exceeded", exceeded, "timeout", timeout) - sequencerSetBytes, _, err := bc.l2Gov.GetSequencerSetBytes(callOpts) - if err != nil { - return fmt.Errorf("failed to get sequencer set verify hash at block %d: %w", callOpts.BlockNumber.Uint64(), err) - } lastBlock, err := bc.l2Clients.BlockByNumber(context.Background(), big.NewInt(int64(bc.lastPackedBlockHeight))) if err != nil { return fmt.Errorf("failed to get last block %d: %w", bc.lastPackedBlockHeight, err) } blockTimestamp := lastBlock.Time() - batchIndex, _, _, err := bc.SealBatch(sequencerSetBytes, blockTimestamp, nil) + batchIndex, _, _, err := bc.SealBatch(blockTimestamp, nil) if err != nil { return fmt.Errorf("failed to seal batch: %w", err) } diff --git a/common/batch/batch_cache_genesis_header_test.go b/common/batch/batch_cache_genesis_header_test.go index 2b984e8f3..dc4873a49 100644 --- a/common/batch/batch_cache_genesis_header_test.go +++ b/common/batch/batch_cache_genesis_header_test.go @@ -20,7 +20,7 @@ var ( globalGenesisBatchHeaderErr error globalGenesisBatchHeaderOnce sync.Once - // Global overrides for cache batch config in tests (instead of updateBatchConfigFromGov). + // Explicit cache batch config used by integration-style tests. globalBatchTimeoutForTest uint64 = 10000000 globalBlockIntervalForTest uint64 = 10000 ) @@ -55,7 +55,7 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { if globalGenesisBatchHeader == nil { return ErrKeyNotFound } - // Use global test knobs instead of querying gov config from chain. + // Use the same explicit values passed to NewBatchCache in these tests. cache.batchTimeOut = globalBatchTimeoutForTest cache.blockInterval = globalBlockIntervalForTest headerCopy := make(BatchHeaderBytes, len(*globalGenesisBatchHeader)) @@ -88,7 +88,7 @@ func initCacheWithGlobalGenesisHeader(cache *BatchCache) error { func TestBatchCacheInitWithGlobalGenesisHeader(t *testing.T) { testDB := openTestKV(t) a := func(uint64) bool { return true } - cache := NewBatchCache(nil, a, 3, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, a, 3, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex done := make(chan error, 1) diff --git a/common/batch/batch_cache_test.go b/common/batch/batch_cache_test.go index 3965fa4aa..f807df0fb 100644 --- a/common/batch/batch_cache_test.go +++ b/common/batch/batch_cache_test.go @@ -27,7 +27,7 @@ func init() { func TestBatchCacheInitServer(t *testing.T) { testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) var batchCacheSyncMu sync.Mutex @@ -60,14 +60,14 @@ func TestBatchCacheInitServer(t *testing.T) { func TestBatchCacheInit(t *testing.T) { testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitAndSyncFromRollup() require.NoError(t, err) } func TestBatchCacheInitByBlockRange(t *testing.T) { testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) } diff --git a/common/batch/batch_query.go b/common/batch/batch_query.go index 21d463294..e150e080f 100644 --- a/common/batch/batch_query.go +++ b/common/batch/batch_query.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math/big" + "strings" "morph-l2/bindings/bindings" @@ -165,13 +166,6 @@ type batchDataInputStruct struct { WithdrawalRoot [32]uint8 `json:"withdrawalRoot"` } -// batchSignatureInputStruct represents the parsed batch signature input structure from ABI -type batchSignatureInputStruct struct { - SignedSequencersBitmap *big.Int `json:"signedSequencersBitmap"` - SequencerSets []uint8 `json:"sequencerSets"` - Signature []uint8 `json:"signature"` -} - // convertBatchDataInput converts the parsed struct to bindings.IRollupBatchDataInput func convertBatchDataInput(s batchDataInputStruct) *bindings.IRollupBatchDataInput { // Convert []uint8 to []byte @@ -189,21 +183,6 @@ func convertBatchDataInput(s batchDataInputStruct) *bindings.IRollupBatchDataInp } } -// convertBatchSignatureInput converts the parsed struct to bindings.IRollupBatchSignatureInput -func convertBatchSignatureInput(s batchSignatureInputStruct) *bindings.IRollupBatchSignatureInput { - // Convert []uint8 to []byte - sequencerSets := make([]byte, len(s.SequencerSets)) - copy(sequencerSets, s.SequencerSets) - signature := make([]byte, len(s.Signature)) - copy(signature, s.Signature) - - return &bindings.IRollupBatchSignatureInput{ - SignedSequencersBitmap: s.SignedSequencersBitmap, - SequencerSets: sequencerSets, - Signature: signature, - } -} - // parseBatchDataInputFromArgs safely parses BatchDataInput from ABI unpacked arguments func parseBatchDataInputFromArgs(args []interface{}) (batchDataInputStruct, error) { if len(args) < 1 { @@ -235,116 +214,49 @@ func parseBatchDataInputFromArgs(args []interface{}) (batchDataInputStruct, erro }, nil } -// parseBatchSignatureInputFromArgs safely parses BatchSignatureInput from ABI unpacked arguments -func parseBatchSignatureInputFromArgs(args []interface{}) (batchSignatureInputStruct, error) { - if len(args) < 2 { - return batchSignatureInputStruct{}, errors.New("insufficient arguments for batch signature input") - } - - // Use comma-ok assertion for safe type checking - rawStruct, ok := args[1].(struct { - SignedSequencersBitmap *big.Int `json:"signedSequencersBitmap"` - SequencerSets []uint8 `json:"sequencerSets"` - Signature []uint8 `json:"signature"` - }) - if !ok { - return batchSignatureInputStruct{}, errors.New("failed to cast batch signature input to expected struct type") - } - - return batchSignatureInputStruct{ - SignedSequencersBitmap: rawStruct.SignedSequencersBitmap, - SequencerSets: rawStruct.SequencerSets, - Signature: rawStruct.Signature, - }, nil -} - -// parseCommitBatchTxData parses the commitBatch transaction's input data to get BatchDataInput and BatchSignatureInput -func parseCommitBatchTxData(txData []byte) (*bindings.IRollupBatchDataInput, *bindings.IRollupBatchSignatureInput, error) { - // Get rollup ABI - rollupAbi, err := bindings.RollupMetaData.GetAbi() - if err != nil { - return nil, nil, err - } - - // Check if method ID is commitBatch - commitBatchMethod, ok := rollupAbi.Methods["commitBatch"] - if !ok { - return nil, nil, errors.New("commitBatch method not found in ABI") - } - - // Check if the first 4 bytes of transaction data match the method ID +// These two compact ABIs freeze the only historical/current commit methods this +// query supports. The pre-Submitter ABI deliberately includes the complete +// BatchSignatureInput tuple so historical calldata is decoded with its real +// layout even though callers only need BatchDataInput. +const preSubmitterCommitABI = `[ + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"},{"components":[{"name":"signedSequencersBitmap","type":"uint256"},{"name":"sequencerSets","type":"bytes"},{"name":"signature","type":"bytes"}],"name":"batchSignatureInput","type":"tuple"}],"name":"commitBatch","outputs":[],"stateMutability":"payable","type":"function"}, + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"},{"components":[{"name":"signedSequencersBitmap","type":"uint256"},{"name":"sequencerSets","type":"bytes"},{"name":"signature","type":"bytes"}],"name":"batchSignatureInput","type":"tuple"},{"name":"_batchHeader","type":"bytes"},{"name":"_batchProof","type":"bytes"}],"name":"commitBatchWithProof","outputs":[],"stateMutability":"nonpayable","type":"function"} +]` + +const submitterCommitABI = `[ + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"}],"name":"commitBatch","outputs":[],"stateMutability":"payable","type":"function"}, + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"},{"name":"_batchHeader","type":"bytes"},{"name":"_batchProof","type":"bytes"}],"name":"commitBatchWithProof","outputs":[],"stateMutability":"nonpayable","type":"function"} +]` + +// parseCommitBatchTxData decodes commitBatch and commitBatchWithProof calldata +// from either side of the Submitter upgrade. No other selector is accepted. +func parseCommitBatchTxData(txData []byte) (*bindings.IRollupBatchDataInput, error) { if len(txData) < 4 { - return nil, nil, errors.New("transaction data too short") + return nil, errors.New("transaction data too short") } - methodID := txData[:4] - if !bytes.Equal(methodID, commitBatchMethod.ID) { - // Try commitBatchWithProof - commitBatchWithProofMethod, ok := rollupAbi.Methods["commitBatchWithProof"] - if !ok { - return nil, nil, errors.New("commitBatchWithProof method not found in ABI") + for _, rawABI := range []string{preSubmitterCommitABI, submitterCommitABI} { + rollupABI, err := abi.JSON(strings.NewReader(rawABI)) + if err != nil { + return nil, fmt.Errorf("parse frozen rollup ABI: %w", err) } - if bytes.Equal(methodID, commitBatchWithProofMethod.ID) { - // Use commitBatchWithProof method to parse - return parseCommitBatchWithProofTxData(txData, rollupAbi) + method, err := rollupABI.MethodById(txData[:4]) + if err != nil { + continue } - return nil, nil, errors.New("transaction is not a commit batch or commitBatchWithProof") - } - - // Parse parameters - args, err := commitBatchMethod.Inputs.Unpack(txData[4:]) - if err != nil { - return nil, nil, err - } - - // Parse BatchDataInput using shared helper - batchDataInputRaw, err := parseBatchDataInputFromArgs(args) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse batch data input: %w", err) - } - batchDataInput := convertBatchDataInput(batchDataInputRaw) - - // Parse BatchSignatureInput using shared helper - batchSignatureInputRaw, err := parseBatchSignatureInputFromArgs(args) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse batch signature input: %w", err) - } - batchSignatureInput := convertBatchSignatureInput(batchSignatureInputRaw) - - return batchDataInput, batchSignatureInput, nil -} - -// parseCommitBatchWithProofTxData parses the commitBatchWithProof transaction's input data -// commitBatchWithProof has 4 parameters: batchDataInput, batchSignatureInput, _batchHeader, _batchProof -func parseCommitBatchWithProofTxData(txData []byte, rollupAbi *abi.ABI) (*bindings.IRollupBatchDataInput, *bindings.IRollupBatchSignatureInput, error) { - commitBatchWithProofMethod, ok := rollupAbi.Methods["commitBatchWithProof"] - if !ok { - return nil, nil, errors.New("commitBatchWithProof method not found in ABI") - } - - // Parse parameters - args, err := commitBatchWithProofMethod.Inputs.Unpack(txData[4:]) - if err != nil { - return nil, nil, err - } - - // Parse BatchDataInput using shared helper - batchDataInputRaw, err := parseBatchDataInputFromArgs(args) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse batch data input: %w", err) - } - batchDataInput := convertBatchDataInput(batchDataInputRaw) - - // Parse BatchSignatureInput using shared helper - batchSignatureInputRaw, err := parseBatchSignatureInputFromArgs(args) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse batch signature input: %w", err) + if method.Name != "commitBatch" && method.Name != "commitBatchWithProof" { + continue + } + args, err := method.Inputs.Unpack(txData[4:]) + if err != nil { + return nil, fmt.Errorf("unpack %s calldata: %w", method.Name, err) + } + batchDataInputRaw, err := parseBatchDataInputFromArgs(args) + if err != nil { + return nil, fmt.Errorf("parse batch data input: %w", err) + } + return convertBatchDataInput(batchDataInputRaw), nil } - batchSignatureInput := convertBatchSignatureInput(batchSignatureInputRaw) - - // The third parameter is _batchHeader (bytes) - // The fourth parameter is _batchProof (bytes) - // These parameters don't need to be returned, but can be used for verification - return batchDataInput, batchSignatureInput, nil + return nil, errors.New("transaction is not commitBatch or commitBatchWithProof") } diff --git a/common/batch/batch_query_test.go b/common/batch/batch_query_test.go new file mode 100644 index 000000000..94ef13b18 --- /dev/null +++ b/common/batch/batch_query_test.go @@ -0,0 +1,108 @@ +package batch + +import ( + "math/big" + "strings" + "testing" + + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + "github.com/stretchr/testify/require" +) + +type historicalBatchSignatureInput struct { + SignedSequencersBitmap *big.Int + SequencerSets []byte + Signature []byte +} + +func TestParseCommitBatchTxDataSupportsOnlyHistoricalAndCurrentCommitSelectors(t *testing.T) { + data := batchDataInputStruct{ + Version: 2, + ParentBatchHeader: []byte{1, 2, 3}, + LastBlockNumber: 12345, + NumL1Messages: 7, + PrevStateRoot: common.HexToHash("0x11"), + PostStateRoot: common.HexToHash("0x22"), + WithdrawalRoot: common.HexToHash("0x33"), + } + signature := historicalBatchSignatureInput{ + SignedSequencersBitmap: big.NewInt(9), + SequencerSets: []byte{0xaa, 0xbb}, + Signature: []byte{0xcc, 0xdd}, + } + + tests := []struct { + name string + rawABI string + method string + selector string + historical bool + }{ + {name: "historical commitBatch", rawABI: preSubmitterCommitABI, method: "commitBatch", selector: "0x428868b5", historical: true}, + {name: "historical commitBatchWithProof", rawABI: preSubmitterCommitABI, method: "commitBatchWithProof", selector: "0x4e8f1d67", historical: true}, + {name: "current commitBatch", rawABI: submitterCommitABI, method: "commitBatch", selector: "0x41f756da"}, + {name: "current commitBatchWithProof", rawABI: submitterCommitABI, method: "commitBatchWithProof", selector: "0x1544ba3a"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + parsedABI, err := abi.JSON(strings.NewReader(test.rawABI)) + require.NoError(t, err) + require.Equal(t, test.selector, hexutil.Encode(parsedABI.Methods[test.method].ID)) + + var calldata []byte + switch { + case test.historical && test.method == "commitBatch": + calldata, err = parsedABI.Pack(test.method, data, signature) + case test.historical: + calldata, err = parsedABI.Pack(test.method, data, signature, []byte{0x12}, []byte{0x34}) + case test.method == "commitBatch": + calldata, err = parsedABI.Pack(test.method, data) + default: + calldata, err = parsedABI.Pack(test.method, data, []byte{0x12}, []byte{0x34}) + } + require.NoError(t, err) + + got, err := parseCommitBatchTxData(calldata) + require.NoError(t, err) + require.Equal(t, data.Version, got.Version) + require.Equal(t, data.ParentBatchHeader, got.ParentBatchHeader) + require.Equal(t, data.LastBlockNumber, got.LastBlockNumber) + require.Equal(t, data.NumL1Messages, got.NumL1Messages) + require.Equal(t, data.PrevStateRoot, got.PrevStateRoot) + require.Equal(t, data.PostStateRoot, got.PostStateRoot) + require.Equal(t, data.WithdrawalRoot, got.WithdrawalRoot) + }) + } + + for _, calldata := range [][]byte{ + {0xde, 0xad, 0xbe, 0xef}, + {0x1e, 0x88, 0x25, 0xbe}, // historical commitState + {0x67, 0xca, 0xa3, 0x7a}, // current commitState + } { + _, err := parseCommitBatchTxData(calldata) + require.Error(t, err) + } +} + +func TestCreateBatchHeaderKeepsWithdrawalRootAndZerosSequencerField(t *testing.T) { + withdrawalRoot := common.HexToHash("0x1234") + cache := &BatchCache{ + batchData: NewBatchData(), + withdrawRoot: withdrawalRoot, + isBatchUpgraded: func(uint64) bool { return true }, + isBatchV2Upgraded: func(uint64) bool { return false }, + parentBatchHeader: nil, + totalL1MessagePopped: 0, + } + header := cache.createBatchHeader(common.HexToHash("0xabcd"), nil, 1) + + gotWithdrawalRoot, err := header.WithdrawalRoot() + require.NoError(t, err) + require.Equal(t, withdrawalRoot, gotWithdrawalRoot) + gotSequencerRoot, err := header.SequencerSetVerifyHash() + require.NoError(t, err) + require.Equal(t, common.Hash{}, gotSequencerRoot) +} diff --git a/common/batch/batch_restart_test.go b/common/batch/batch_restart_test.go index 87cdf1393..48a2a3547 100644 --- a/common/batch/batch_restart_test.go +++ b/common/batch/batch_restart_test.go @@ -13,7 +13,6 @@ import ( "github.com/morph-l2/go-ethereum/accounts/abi/bind" "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" "github.com/stretchr/testify/require" ) @@ -50,17 +49,16 @@ func init() { func Test_GetFinalizeBatchHeader(t *testing.T) { testDB := openTestKV(t) - bc := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + bc := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) headerBytes, err := bc.getLastFinalizeBatchHeaderFromRollupByIndex(0) require.NoError(t, err) t.Log("headerBytes", hex.EncodeToString(headerBytes.Bytes())) } func Test_CommitBatchParse(t *testing.T) { - data, signature, err := getCommitBatchDataByIndex(5357) + data, err := getCommitBatchDataByIndex(5357) require.NoError(t, err) t.Log("data", data) - t.Log("signature", signature) t.Log("data.Version", data.Version) t.Log("data.ParentBatchHeader", hex.EncodeToString(data.ParentBatchHeader)) t.Log("data.LastBlockNumber", data.LastBlockNumber) @@ -73,12 +71,9 @@ func Test_CommitBatchParse(t *testing.T) { func TestBatchRestartInit(t *testing.T) { testDB := openTestKV(t) - sequencerSetBytes, sequencerSetVerifyHash, err := l2Gov.GetSequencerSetBytes(nil) - require.NoError(t, err) - t.Log("sequencer set verify hash", hex.EncodeToString(sequencerSetVerifyHash[:])) ci, fi := getInfosFromContract() t.Log("commit index", ci, " ", "finalize index", fi) - bc := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + bc := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) startBlockNum, endBlockNum, err := getFirstUnFinalizeBatchBlockNumRange(fi) require.NoError(t, err) startBlockNum = new(big.Int).Add(startBlockNum, new(big.Int).SetUint64(1)) @@ -110,7 +105,7 @@ func TestBatchRestartInit(t *testing.T) { t.Logf("First unfinalize batch index: %d, block range: %d - %d", firstUnfinalizedIndex, startBlockNum.Uint64(), endBlockNum.Uint64()) // Fetch blocks from L2 client in this range and assemble batchHeader - assembledBatchHeader, err := assembleBatchHeaderFromL2Blocks(bc, startBlockNum.Uint64(), endBlockNum.Uint64(), sequencerSetBytes, l2Client, l2Gov) + assembledBatchHeader, err := assembleBatchHeaderFromL2Blocks(bc, startBlockNum.Uint64(), endBlockNum.Uint64(), l2Client, l2Gov) require.NoError(t, err, "failed to assemble batch header from L2 blocks") t.Log("assembled batch header success", hex.EncodeToString(assembledBatchHeader.Bytes())) // Verify the assembled batchHeader @@ -120,7 +115,7 @@ func TestBatchRestartInit(t *testing.T) { assembledBatchHash, err := assembledBatchHeader.Hash() require.NoError(t, err) - batchDataInput, batchSignatureInput, err := getCommitBatchDataByIndex(firstUnfinalizedIndex) + batchDataInput, err := getCommitBatchDataByIndex(firstUnfinalizedIndex) require.NoError(t, err) t.Logf("batchDataInput.Version=%d", batchDataInput.Version) require.Equal(t, hex.EncodeToString(batchDataInput.ParentBatchHeader), hex.EncodeToString(headerBytes.Bytes())) @@ -136,8 +131,7 @@ func TestBatchRestartInit(t *testing.T) { require.Equal(t, batchDataInput.PostStateRoot[:], postStateRoot.Bytes()) // Compare assembledBatchHeader with the batch header built from commitBatch data - // Note: batchDataInput and batchSignatureInput can be used to verify data, but need to build a complete batch header - compareBatchHeaderWithCommitData(t, assembledBatchHeader, batchDataInput, batchSignatureInput, sequencerSetVerifyHash) + compareBatchHeaderWithCommitData(t, assembledBatchHeader, batchDataInput) committedBatchHash, err := rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(assembledBatchIndex)) require.NoError(t, err) @@ -147,7 +141,7 @@ func TestBatchRestartInit(t *testing.T) { } // compareBatchHeaderWithCommitData compares the assembled batch header with information extracted from commitBatch data -func compareBatchHeaderWithCommitData(t *testing.T, assembledBatchHeader *BatchHeaderBytes, batchDataInput *bindings.IRollupBatchDataInput, batchSignatureInput *bindings.IRollupBatchSignatureInput, sequencerSetVerifyHash common.Hash) { +func compareBatchHeaderWithCommitData(t *testing.T, assembledBatchHeader *BatchHeaderBytes, batchDataInput *bindings.IRollupBatchDataInput) { t.Logf("\n=== Comparing assembled batch header with commitBatch data ===") // Compare Version @@ -223,21 +217,10 @@ func compareBatchHeaderWithCommitData(t *testing.T, assembledBatchHeader *BatchH t.Logf("✓ WithdrawalRoot: %x (match)", withdrawRoot) } - // Compare SequencerSetVerifyHash - sequencerSetsHash := crypto.Keccak256Hash(batchSignatureInput.SequencerSets) + // New and recovered post-upgrade batches keep the historical field as zero. seqHash, err := assembledBatchHeader.SequencerSetVerifyHash() require.NoError(t, err) - if seqHash != sequencerSetsHash { - t.Errorf("❌ SequencerSetVerifyHash mismatch: assembled=%x, from SequencerSets=%x", seqHash, sequencerSetsHash) - } else { - t.Logf("✓ SequencerSetVerifyHash: %x (match)", seqHash) - } - - if seqHash != sequencerSetVerifyHash { - t.Errorf("❌ SequencerSetVerifyHash mismatch with provided hash: assembled=%x, provided=%x", seqHash, sequencerSetVerifyHash) - } else { - t.Logf("✓ SequencerSetVerifyHash matches provided hash: %x", sequencerSetVerifyHash) - } + require.Equal(t, common.Hash{}, seqHash) } func min(a, b int) int { @@ -346,14 +329,14 @@ func getFirstUnFinalizeBatchBlockNumRange(lastFinalizedBatchIndex *big.Int) (*bi return fis.BlockNumber, ufis.BlockNumber, nil } -// getCommitBatchDataByIndex gets batchDataInput and batchSignatureInput with the specified index from the rollup contract's CommitBatch event +// getCommitBatchDataByIndex gets BatchDataInput from the rollup contract's CommitBatch event. // Reference the implementation of getLastFinalizeBatchHeaderByIndex // Query is limited to 10000 block heights, starting from the latest height and querying backwards until data is found -func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, *bindings.IRollupBatchSignatureInput, error) { +func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, error) { // Get the current latest block height latestBlock, err := l1Client.BlockNumber(context.Background()) if err != nil { - return nil, nil, fmt.Errorf("failed to get latest block number: %w", err) + return nil, fmt.Errorf("failed to get latest block number: %w", err) } const blockRange = uint64(10000) // Query 10000 blocks each time @@ -395,13 +378,13 @@ func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, * // Get transaction details tx, _, err := l1Client.TransactionByHash(context.Background(), txHash) if err != nil { - return nil, nil, fmt.Errorf("failed to get transaction by hash: %w", err) + return nil, fmt.Errorf("failed to get transaction by hash: %w", err) } - // Parse commitBatch transaction data to get batchDataInput and batchSignatureInput - batchDataInput, batchSignatureInput, err := parseCommitBatchTxData(tx.Data()) + // Parse commitBatch transaction data to get BatchDataInput. + batchDataInput, err := parseCommitBatchTxData(tx.Data()) if err != nil { - return nil, nil, fmt.Errorf("failed to parse commit batch data: %w", err) + return nil, fmt.Errorf("failed to parse commit batch data: %w", err) } // Verify if batch index matches (by checking batchIndex in parentBatchHeader) @@ -410,7 +393,7 @@ func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, * parentBatchIndex, err := parentHeader.BatchIndex() if err == nil && parentBatchIndex+1 == index { commitEventIter.Close() - return batchDataInput, batchSignatureInput, nil + return batchDataInput, nil } } } @@ -423,7 +406,7 @@ func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, * endBlock = startBlock - 1 } - return nil, nil, ErrBatchNotFound + return nil, ErrBatchNotFound } // assembleBatchHeaderFromL2Blocks fetches blocks from L2 client in the specified range and assembles batchHeader @@ -431,7 +414,6 @@ func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, * // - bc: BatchCache instance (parentBatchHeader and prevStateRoot already initialized) // - startBlockNum: starting block number // - endBlockNum: ending block number -// - sequencerSetVerifyHash: sequencer set verification hash // - l2Client: L2 client // // Returns: @@ -440,7 +422,6 @@ func getCommitBatchDataByIndex(index uint64) (*bindings.IRollupBatchDataInput, * func assembleBatchHeaderFromL2Blocks( bc *BatchCache, startBlockNum, endBlockNum uint64, - sequencerBytes []byte, l2Client *ethclient.Client, l2Gov L2GovCaller, ) (*BatchHeaderBytes, error) { @@ -478,7 +459,7 @@ func assembleBatchHeaderFromL2Blocks( blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeaderBytes, _, err := bc.SealBatch(sequencerBytes, blockTimestamp, nil) + batchIndex, batchHeaderBytes, _, err := bc.SealBatch(blockTimestamp, nil) if err != nil { return nil, fmt.Errorf("failed to seal batch: %w", err) } diff --git a/common/batch/batch_storage_test.go b/common/batch/batch_storage_test.go index 9ceee7da2..fceea3dcc 100644 --- a/common/batch/batch_storage_test.go +++ b/common/batch/batch_storage_test.go @@ -233,7 +233,7 @@ func TestSealBatchPropagatesStoreErrorAndKeepsState(t *testing.T) { originalBatchData := bc.batchData originalParent := bc.parentBatchHeader - _, _, _, err := bc.SealBatch([]byte{1}, 1, nil) + _, _, _, err := bc.SealBatch(1, nil) require.ErrorIs(t, err, errWriteBatchUnavailable) require.Empty(t, bc.sealedBatches) require.Empty(t, bc.sealedBatchHeaders) diff --git a/common/batch/commit_test.go b/common/batch/commit_test.go index c704b885f..f6d74ebf3 100644 --- a/common/batch/commit_test.go +++ b/common/batch/commit_test.go @@ -13,7 +13,6 @@ import ( "morph-l2/common/blob" "github.com/holiman/uint256" - "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/consensus/misc/eip4844" ethtypes "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto" @@ -34,7 +33,7 @@ func TestRollupWithProof(t *testing.T) { } testDB := openTestKV(t) - cache := NewBatchCache(nil, nil, 2, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) + cache := NewBatchCache(nil, nil, 2, globalBlockIntervalForTest, globalBatchTimeoutForTest, l1Client, &SingleL2Client{C: l2Client}, rollupContract, l2Gov, testDB) err := cache.InitFromRollupByRange() require.NoError(t, err) @@ -53,11 +52,6 @@ func TestRollupWithProof(t *testing.T) { batch, err := cache.Get(latestCommitBatchIndex.Uint64() + 1) require.NoError(t, err) - h := crypto.Keccak256Hash(batch.CurrentSequencerSetBytes) - t.Log("sequencer verify hash:", h.String()) - - signature, err := buildSigInput(batch) - require.NoError(t, err) rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(batch.Version), ParentBatchHeader: batch.ParentBatchHeader, @@ -70,7 +64,7 @@ func TestRollupWithProof(t *testing.T) { tip, gasFeeCap, blobFee, head, err := getGasTipAndCap(l1Client) require.NoError(t, err) - calldata, err := abi.Pack("commitBatch", rollupBatch, *signature) + calldata, err := abi.Pack("commitBatch", rollupBatch) require.NoError(t, err) nonce, err := l1Client.NonceAt(context.Background(), address, nil) require.NoError(t, err) @@ -186,15 +180,6 @@ func getGasTipAndCap(l1client *ethclient.Client) (*big.Int, *big.Int, *big.Int, return tip, gasFeeCap, blobFee, head, nil } -func buildSigInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { - sigData := &bindings.IRollupBatchSignatureInput{ - SignedSequencersBitmap: common.Big0, - SequencerSets: batch.CurrentSequencerSetBytes, - Signature: []byte("0x"), - } - return sigData, nil -} - func sendTx(client *ethclient.Client, txFeeLimit uint64, tx *ethtypes.Transaction) error { if txFeeLimit > 0 { var fee uint64 diff --git a/common/batch/interfaces.go b/common/batch/interfaces.go index 739ef422c..7dc43848d 100644 --- a/common/batch/interfaces.go +++ b/common/batch/interfaces.go @@ -73,18 +73,15 @@ type RollupBatchReader interface { LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) } -// L2GovCaller reads batch-related Gov / bridge / sequencer data on L2. +// L2GovCaller reads the withdrawal tree root used when assembling batches. type L2GovCaller interface { - BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) - BatchTimeout(opts *bind.CallOpts) (*big.Int, error) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) - GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) } diff --git a/common/batch/l2_gov.go b/common/batch/l2_gov.go index acfe0c0d0..641d81312 100644 --- a/common/batch/l2_gov.go +++ b/common/batch/l2_gov.go @@ -1,24 +1,18 @@ package batch import ( - "bytes" "fmt" - "math/big" "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/common/hexutil" - "github.com/morph-l2/go-ethereum/crypto" ) -// L2Gov bundles read-only L2 contracts used when assembling rollup batches. +// L2Gov provides the withdrawal-root read used when assembling rollup batches. +// The name is kept to avoid a broad caller rename during this cleanup. type L2Gov struct { - sequencerContract *bindings.SequencerCaller l2MessagePasserContract *bindings.L2ToL1MessagePasserCaller - govContract *bindings.GovCaller } // NewL2Gov builds an L2Gov using any ContractCaller (e.g. *ethclient.Client or a multi-client backend). @@ -26,57 +20,16 @@ func NewL2Gov(backend bind.ContractCaller) (*L2Gov, error) { if backend == nil { return nil, fmt.Errorf("nil contract backend") } - sequencerContract, err := bindings.NewSequencerCaller(predeploys.SequencerAddr, backend) - if err != nil { - return nil, err - } l2MessagePasserContract, err := bindings.NewL2ToL1MessagePasserCaller(predeploys.L2ToL1MessagePasserAddr, backend) if err != nil { return nil, err } - govContract, err := bindings.NewGovCaller(predeploys.GovAddr, backend) - if err != nil { - return nil, err - } return &L2Gov{ - sequencerContract: sequencerContract, l2MessagePasserContract: l2MessagePasserContract, - govContract: govContract, }, nil } -// SequencerSetVerifyHash gets the sequencer set verify hash from the Sequencer contract. -func (c *L2Gov) SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) { - return c.sequencerContract.SequencerSetVerifyHash(opts) -} - // GetTreeRoot gets the tree root from the L2ToL1MessagePasser contract. func (c *L2Gov) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) { return c.l2MessagePasserContract.GetTreeRoot(opts) } - -// BatchBlockInterval gets the batch block interval from the Gov contract. -func (c *L2Gov) BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) { - return c.govContract.BatchBlockInterval(opts) -} - -// BatchTimeout gets the batch timeout from the Gov contract. -func (c *L2Gov) BatchTimeout(opts *bind.CallOpts) (*big.Int, error) { - return c.govContract.BatchTimeout(opts) -} - -// GetSequencerSetBytes returns sequencer set bytes after hash consistency check. -func (c *L2Gov) GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) { - hash, err := c.sequencerContract.SequencerSetVerifyHash(opts) - if err != nil { - return nil, common.Hash{}, err - } - setBytes, err := c.sequencerContract.GetSequencerSetBytes(opts) - if err != nil { - return nil, common.Hash{}, err - } - if bytes.Equal(hash[:], crypto.Keccak256Hash(setBytes).Bytes()) { - return setBytes, hash, nil - } - return nil, common.Hash{}, fmt.Errorf("sequencer set hash verify failed %v: %v", hexutil.Encode(setBytes), common.BytesToHash(hash[:]).String()) -} From 6990b58440fe26d4ea94704667fde25075900898 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:03:42 +0800 Subject: [PATCH 25/38] feat(tx-submitter): submit through staked membership --- tx-submitter/README.md | 6 +- tx-submitter/entry.go | 43 +- tx-submitter/event/indexer.go | 145 ------- tx-submitter/event/storage.go | 109 ----- tx-submitter/event/storage_test.go | 40 -- tx-submitter/flags/flags.go | 89 +--- tx-submitter/iface/client.go | 4 +- tx-submitter/iface/rollup.go | 31 +- tx-submitter/metrics/metrics.go | 12 - tx-submitter/mock/event_storage.go | 26 -- tx-submitter/mock/l1staking.go | 62 --- tx-submitter/mock/l2client.go | 50 +-- tx-submitter/mock/rollup.go | 43 +- tx-submitter/mock/submitter.go | 34 ++ tx-submitter/params/leveldb_keys.go | 5 - tx-submitter/services/batch_fecher.go | 3 +- tx-submitter/services/batch_fetcher_test.go | 20 + tx-submitter/services/rollup.go | 381 ++---------------- .../services/rollup_commit_rebuild_test.go | 72 ++++ tx-submitter/services/rollup_handle_test.go | 66 ++- tx-submitter/services/rollup_test.go | 1 - tx-submitter/services/rotator.go | 158 -------- tx-submitter/types/batch_cache.go | 19 +- tx-submitter/types/batch_cache_test.go | 30 ++ tx-submitter/types/l2Caller.go | 2 +- tx-submitter/utils/config.go | 58 ++- tx-submitter/utils/config_test.go | 14 + tx-submitter/utils/utils.go | 10 - 28 files changed, 311 insertions(+), 1222 deletions(-) delete mode 100644 tx-submitter/event/indexer.go delete mode 100644 tx-submitter/event/storage.go delete mode 100644 tx-submitter/event/storage_test.go delete mode 100644 tx-submitter/mock/event_storage.go delete mode 100644 tx-submitter/mock/l1staking.go create mode 100644 tx-submitter/mock/submitter.go delete mode 100644 tx-submitter/params/leveldb_keys.go create mode 100644 tx-submitter/services/batch_fetcher_test.go create mode 100644 tx-submitter/services/rollup_commit_rebuild_test.go delete mode 100644 tx-submitter/services/rotator.go create mode 100644 tx-submitter/types/batch_cache_test.go create mode 100644 tx-submitter/utils/config_test.go diff --git a/tx-submitter/README.md b/tx-submitter/README.md index 428197da2..0869e0044 100644 --- a/tx-submitter/README.md +++ b/tx-submitter/README.md @@ -11,6 +11,6 @@ ```bash cast call $ROLLUP_ADDR "lastFinalizedBatchIndex()" -r $L1RPC cast call $ROLLUP_ADDR "lastCommittedBatchIndex()" -r $L1RPC -cast call $L2_SEQUENCER_ADDR "getSequencerSet2()(address[])" -r $L2RPC -cast call $L1_STAKING_ADDR "getActiveStakers()(address[])" -r $L1RPC -``` \ No newline at end of file +cast call $SUBMITTER_ADDR "isActive(address)(bool)" $WALLET_ADDR -r $L1RPC +cast call $ROLLUP_ADDR "batchBlobVersionedHashes(uint256)(bytes32)" $BATCH_INDEX -r $L1RPC +``` diff --git a/tx-submitter/entry.go b/tx-submitter/entry.go index b67cf0da9..dcda8246b 100644 --- a/tx-submitter/entry.go +++ b/tx-submitter/entry.go @@ -6,7 +6,6 @@ import ( "crypto/rsa" "fmt" "io" - "math/big" "os" "os/signal" "strings" @@ -14,7 +13,6 @@ import ( "morph-l2/bindings/bindings" "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/metrics" @@ -23,7 +21,6 @@ import ( "morph-l2/tx-submitter/utils" "github.com/morph-l2/externalsign" - "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" @@ -50,12 +47,11 @@ func Main() func(ctx *cli.Context) error { "l1_rpc", cfg.L1EthRpc, "l2_rpcs", cfg.L2EthRpcs, "rollup_addr", cfg.RollupAddress, - "l2_sequencer_addr", cfg.L2SequencerAddress, - "l2_gov_addr", cfg.L2GovAddress, - "l1_staking_addr", cfg.L1StakingAddress, + "submitter_addr", cfg.SubmitterAddress, + "batch_block_interval", cfg.BatchBlockInterval, + "batch_timeout", cfg.BatchTimeout, "fee_limit", cfg.TxFeeLimit, "finalize_enable", cfg.Finalize, - "priority_rollup_enable", cfg.PriorityRollup, "rollup_interval", cfg.RollupInterval.String(), "finalize_interval", cfg.FinalizeInterval.String(), "tx_process_interval", cfg.TxProcessInterval.String(), @@ -64,7 +60,6 @@ func Main() func(ctx *cli.Context) error { "journal_path", cfg.JournalFilePath, "gas_rough_estimate", cfg.RoughEstimateGas, "gas_limit_buffer", cfg.GasLimitBuffer, - "rotator_buffer", cfg.RotatorBuffer, "rough_estimate_gas", cfg.RoughEstimateGas, "rough_estimate_base_gas", cfg.RollupTxGasBase, "rough_estimate_per_l1_msg", cfg.RollupTxGasPerL1Msg, @@ -153,10 +148,10 @@ func Main() func(ctx *cli.Context) error { return fmt.Errorf("failed to get rollup abi: %w", err) } - // l1 staking - l1Staking, err := bindings.NewL1Staking(common.HexToAddress(cfg.L1StakingAddress), l1Client) + // Submitter membership is the only submission eligibility source. + submitter, err := bindings.NewSubmitter(common.HexToAddress(cfg.SubmitterAddress), l1Client) if err != nil { - return fmt.Errorf("failed to connect to l1 staking contract") + return fmt.Errorf("failed to connect to Submitter contract: %w", err) } var rsaPriv *rsa.PrivateKey @@ -178,32 +173,10 @@ func Main() func(ctx *cli.Context) error { } - l1StakingAbi, err := bindings.L1StakingMetaData.GetAbi() - if err != nil { - return fmt.Errorf("failed to get l1 staking abi: %w", err) - } - // new event listener - filter := ethereum.FilterQuery{ - Addresses: []common.Address{common.HexToAddress(cfg.L1StakingAddress)}, - Topics: [][]common.Hash{ - {l1StakingAbi.Events["StakersRemoved"].ID}, - }, - } - ldb, err := db.New(cfg.LeveldbPathName) if err != nil { return fmt.Errorf("failed to connect leveldb: %w", err) } - eventInfoStorage := event.NewEventInfoStorage(ldb) - err = eventInfoStorage.Load() - if err != nil { - return err - } - eventIndexer := event.NewEventIndexer(l1Client, new(big.Int).SetUint64(cfg.L1StakingDeployedBlockNumber), filter, cfg.EventIndexStep, eventInfoStorage) - // new rotator - rotator := services.NewRotator(common.HexToAddress(cfg.L2SequencerAddress), common.HexToAddress(cfg.L2GovAddress), eventIndexer) - // start rorator event indexer - rotator.StartEventIndexer() // block monitor bm := l1checker.NewBlockMonitor(cfg.BlockNotIncreasedThreshold, l1Client) @@ -220,17 +193,15 @@ func Main() func(ctx *cli.Context) error { l1Client, l2Clients, l1Rollup, - l1Staking, + submitter, chainID, privKey, rollupAddr, rollupAbi, cfg, rsaPriv, - rotator, ldb, bm, - eventInfoStorage, l2Caller, ) diff --git a/tx-submitter/event/indexer.go b/tx-submitter/event/indexer.go deleted file mode 100644 index dc517ba72..000000000 --- a/tx-submitter/event/indexer.go +++ /dev/null @@ -1,145 +0,0 @@ -package event - -import ( - "context" - "math/big" - "time" - - "github.com/morph-l2/go-ethereum" - "github.com/morph-l2/go-ethereum/core/types" - "github.com/morph-l2/go-ethereum/ethclient" - "github.com/morph-l2/go-ethereum/log" -) - -type EventIndexer struct { - client *ethclient.Client - deployBlock *big.Int // Block number of contract deployment - filterQuery ethereum.FilterQuery - indexStep uint64 // index step - storage IEventStorage -} - -func NewEventIndexer(client *ethclient.Client, deployedBlock *big.Int, filter ethereum.FilterQuery, indexStep uint64, storage IEventStorage) *EventIndexer { - return &EventIndexer{ - client: client, - deployBlock: deployedBlock, - filterQuery: filter, - indexStep: indexStep, - storage: storage, - } -} - -func (l *EventIndexer) Index() { - log.Info("event indexer started") - - if l.storage.BlockProcessed() == 0 { - l.storage.SetBlockProcessed(l.deployBlock.Uint64()) - err := l.storage.Store() - if err != nil { - log.Error("failed to store initial block number", "error", err) - } - } - - // Create a ticker that triggers every minute - ticker := time.NewTicker(time.Second * 15) - defer ticker.Stop() - - for range ticker.C { - // Get the current block number - currentBlock, err := l.client.BlockNumber(context.Background()) - if err != nil { - log.Error("failed to get current block number", "error", err) - continue - } - - if currentBlock <= l.storage.BlockProcessed() { - log.Info("no new block to index", "current_block", currentBlock, "last_processed_block", l.storage.BlockProcessed()) - continue - } - - // Perform indexing operation - indexedEventInfo, err := l.index(l.client, big.NewInt(int64(l.storage.BlockProcessed())), big.NewInt(int64(currentBlock))) - if err != nil { - log.Error("indexing operation failed", "error", err) - continue - } - - if indexedEventInfo != nil { - l.storage.SetBlockProcessed(indexedEventInfo.BlockProcessed) - } else { - l.storage.SetBlockProcessed(currentBlock) - } - - // Update storage - err = l.storage.Store() - if err != nil { - log.Error("event index complete, failed to update storage", "error", err) - } else { - info := l.storage.EventInfo() - log.Info("event index complete, storage updated", "processed_block", info.BlockProcessed, "block_time", info.BlockTime) - } - } -} - -// filter logs from from_block to to_block -// if the range is too large, will divide the range -func (ei *EventIndexer) index(client *ethclient.Client, fromBlock, toBlock *big.Int) (*EventInfo, error) { - - endBlock := toBlock.Uint64() - startBlock := endBlock - ei.indexStep - lastProcessedBlock := fromBlock.Uint64() - if startBlock < lastProcessedBlock { - startBlock = lastProcessedBlock - } - logFilter := ei.GetFilter() - - // Find the last unprocessed log - for endBlock >= lastProcessedBlock && endBlock > startBlock { - logFilter.FromBlock = big.NewInt(int64(startBlock)) - logFilter.ToBlock = big.NewInt(int64(endBlock)) - historicalLogs, err := client.FilterLogs(context.Background(), logFilter) - if err != nil { - log.Error("Failed to get historical logs", - "error", err, - "start_block", startBlock, - "end_block", endBlock, - ) - continue - } else { - if len(historicalLogs) > 0 { - latestLog := historicalLogs[len(historicalLogs)-1] - var block *types.Block - for { - block, err = client.BlockByNumber(context.Background(), new(big.Int).SetUint64(latestLog.BlockNumber)) - if err != nil { - log.Error("Failed to get block", "error", err) - time.Sleep(time.Second * 5) - continue - } else { - return &EventInfo{ - BlockProcessed: toBlock.Uint64(), - BlockTime: block.Time(), - }, nil - } - } - } - log.Info("backward indexing", "block_num", startBlock, "target_num", lastProcessedBlock) - // update query range - endBlock = startBlock - if endBlock <= lastProcessedBlock+ei.indexStep { - startBlock = lastProcessedBlock + 1 - } else { - startBlock = endBlock - ei.indexStep - } - - } - } - return nil, nil -} - -func (l *EventIndexer) GetFilter() ethereum.FilterQuery { - return l.filterQuery -} -func (l *EventIndexer) GetStorage() IEventStorage { - return l.storage -} diff --git a/tx-submitter/event/storage.go b/tx-submitter/event/storage.go deleted file mode 100644 index dcec97af0..000000000 --- a/tx-submitter/event/storage.go +++ /dev/null @@ -1,109 +0,0 @@ -package event - -import ( - "encoding/json" - "errors" - "fmt" - "sync" - - "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/params" -) - -type IEventStorage interface { - Store() error - Load() error - BlockProcessed() uint64 - SetBlockProcessed(blockNum uint64) - BlockTime() uint64 - SetBlockTime(blockTime uint64) - EventInfo() EventInfo -} - -type EventInfo struct { - BlockTime uint64 `json:"block_time"` // event emit time - BlockProcessed uint64 `json:"block_processed"` // block processed -} - -type EventInfoStorage struct { - eventInfo EventInfo - db db.Database - mu sync.RWMutex -} - -func NewEventInfoStorage(db db.Database) *EventInfoStorage { - return &EventInfoStorage{ - db: db, - } -} - -func (e *EventInfoStorage) Store() error { - // Convert struct to JSON string - jsonData, err := json.Marshal(e.eventInfo) - if err != nil { - return fmt.Errorf("failed to convert struct to JSON: %w", err) - } - - e.mu.Lock() - defer e.mu.Unlock() - // Write JSON data to file - err = e.db.PutString(params.EventInfoKey, string(jsonData)) - if err != nil { - return fmt.Errorf("failed to write to db: err=%w, data=%v", err, jsonData) - } - return nil -} - -func (e *EventInfoStorage) Load() error { - e.mu.Lock() - defer e.mu.Unlock() - - jsonStr, err := e.db.GetString(params.EventInfoKey) - if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { - // Initialize with default values if not found - e.eventInfo = EventInfo{} - return nil - } - return fmt.Errorf("failed to read from db: %w", err) - } - - err = json.Unmarshal([]byte(jsonStr), &e.eventInfo) - if err != nil { - return fmt.Errorf("failed to parse JSON: %w", err) - } - - return nil -} - -func (e *EventInfoStorage) BlockProcessed() uint64 { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo.BlockProcessed -} - -func (e *EventInfoStorage) SetBlockProcessed(blockNum uint64) { - e.mu.Lock() - defer e.mu.Unlock() - e.eventInfo.BlockProcessed = blockNum -} - -func (e *EventInfoStorage) BlockTime() uint64 { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo.BlockTime -} - -func (e *EventInfoStorage) SetBlockTime(blockTime uint64) { - e.mu.Lock() - defer e.mu.Unlock() - e.eventInfo.BlockTime = blockTime -} - -// EventInfo returns a copy of the current event info. -// This ensures thread safety without exposing the internal state. -func (e *EventInfoStorage) EventInfo() EventInfo { - e.mu.RLock() - defer e.mu.RUnlock() - return e.eventInfo -} diff --git a/tx-submitter/event/storage_test.go b/tx-submitter/event/storage_test.go deleted file mode 100644 index 2299bab52..000000000 --- a/tx-submitter/event/storage_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package event - -import ( - "morph-l2/tx-submitter/db" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestEventInfoStorage(t *testing.T) { - // Create a unique test directory - testDir := filepath.Join(t.TempDir(), "testleveldb") - - // Cleanup before test (in case it exists) - os.RemoveAll(testDir) - - // Cleanup after test - t.Cleanup(func() { - os.RemoveAll(testDir) - }) - - db, err := db.New(testDir) - require.NoError(t, err) - storage := NewEventInfoStorage(db) - err = storage.Load() - require.NoError(t, err) - - storage.SetBlockTime(100) - storage.SetBlockProcessed(100) - err = storage.Store() - require.NoError(t, err) - - storage2 := NewEventInfoStorage(db) - err = storage2.Load() - require.NoError(t, err) - require.Equal(t, storage.BlockTime(), storage2.BlockTime()) - require.Equal(t, storage.BlockProcessed(), storage2.BlockProcessed()) -} diff --git a/tx-submitter/flags/flags.go b/tx-submitter/flags/flags.go index cdbf1405d..f91098702 100644 --- a/tx-submitter/flags/flags.go +++ b/tx-submitter/flags/flags.go @@ -3,8 +3,6 @@ package flags import ( "time" - "morph-l2/bindings/predeploys" - "github.com/urfave/cli" ) @@ -59,11 +57,23 @@ var ( Required: true, EnvVar: prefixEnvVar("ROLLUP_ADDRESS"), } - L1StakingAddressFlag = cli.StringFlag{ - Name: "l1_staking_address", - Usage: "Address of the staking contract", + SubmitterAddressFlag = cli.StringFlag{ + Name: "submitter_address", + Usage: "Address of the Submitter contract", + Required: true, + EnvVar: prefixEnvVar("SUBMITTER_ADDRESS"), + } + BatchBlockIntervalFlag = cli.Uint64Flag{ + Name: "batch_block_interval", + Usage: "Maximum number of L2 blocks accumulated before sealing a batch (0 disables this trigger)", Required: true, - EnvVar: prefixEnvVar("L1_STAKING_ADDRESS"), + EnvVar: prefixEnvVar("BATCH_BLOCK_INTERVAL"), + } + BatchTimeoutFlag = cli.Uint64Flag{ + Name: "batch_timeout", + Usage: "Maximum batch accumulation time in seconds (0 disables this trigger)", + Required: true, + EnvVar: prefixEnvVar("BATCH_TIMEOUT"), } // finalize flags @@ -74,30 +84,6 @@ var ( Required: true, } - // decentralize config - PriorityRollupFlag = cli.BoolFlag{ - Name: "priority_rollup", - Usage: "Enable priority rollup", - EnvVar: prefixEnvVar("PRIORITY_ROLLUP"), - Required: true, - } - - // L2 contract - L2SequencerAddressFlag = cli.StringFlag{ - Name: "l2_sequencer_address", - Usage: "Address of the sequencer contract", - Required: false, - EnvVar: prefixEnvVar("L2_SEQUENCER_ADDRESS"), - Value: predeploys.Sequencer, - } - L2GovAddressFlag = cli.StringFlag{ - Name: "l2_gov_address", - Usage: "Address of the gov contract", - Required: false, - EnvVar: prefixEnvVar("L2_GOV_ADDRESS"), - Value: predeploys.Gov, - } - /* Optional Flags */ LogLevelFlag = cli.StringFlag{ Name: "log_level", @@ -206,14 +192,6 @@ var ( EnvVar: prefixEnvVar("JOURNAL_FILE_PATH"), Value: "journal.rlp", } - // listener processed block record path - StakingEventStoreFileFlag = cli.StringFlag{ - Name: "staking_event_store_filename", - Usage: "The file name of the storage", - EnvVar: prefixEnvVar("STAKING_EVENT_STORE_FILENAME"), - Value: "StakingEventStore.json", - } - TipFeeBumpFlag = cli.Uint64Flag{ Name: "TIP_FEE_BUMP", Usage: "The fee bump for tip", @@ -280,7 +258,7 @@ var ( ExternalSignRsaPriv = cli.StringFlag{ Name: "external_rsa_priv", Usage: "The rsa private key of the external sign", - EnvVar: "SEQUENCER_EXTERNAL_SIGN_RSA_PRIV", // use sequencer rsa from xxx + EnvVar: "SEQUENCER_EXTERNAL_SIGN_RSA_PRIV", // Legacy environment name retained for compatibility. } RoughEstimateGasFlag = cli.BoolFlag{ Name: "rough_estimate_gas", @@ -288,28 +266,6 @@ var ( EnvVar: prefixEnvVar("ROUGH_ESTIMATE_GAS"), } - RotatorBufferFlag = cli.Int64Flag{ - Name: "rotator_buffer", - Usage: "rotation interval buffer", - Value: 15, - EnvVar: prefixEnvVar("ROTATOR_BUFFER"), - } - - // l1 staking deployed blocknum - L1StakingDeployedBlocknumFlag = cli.Uint64Flag{ - Name: "l1_staking_deployed_blocknum", - Usage: "The deployed block number of L1Staking", - EnvVar: prefixEnvVar("L1_STAKING_DEPLOYED_BLOCKNUM"), - Required: true, - } - - // event indexer - EventIndexStepFlag = cli.Uint64Flag{ - Name: "event_index_step", - Usage: "The step size for event indexing", - Value: 100, - EnvVar: prefixEnvVar("EVENT_INDEX_STEP"), - } LeveldbPathNameFlag = cli.StringFlag{ Name: "leveldb_path_name", Usage: "The path name of the leveldb", @@ -356,10 +312,10 @@ var requiredFlags = []cli.Flag{ RollupAddressFlag, TxTimeoutFlag, FinalizeFlag, - PriorityRollupFlag, TxFeeLimitFlag, - L1StakingAddressFlag, - L1StakingDeployedBlocknumFlag, + SubmitterAddressFlag, + BatchBlockIntervalFlag, + BatchTimeoutFlag, } var optionalFlags = []cli.Flag{ @@ -384,8 +340,6 @@ var optionalFlags = []cli.Flag{ JournalFlag, PrivateKeyFlag, - L2SequencerAddressFlag, - L2GovAddressFlag, TipFeeBumpFlag, MaxTipFlag, MinTipFlag, @@ -400,9 +354,6 @@ var optionalFlags = []cli.Flag{ ExternalSignUrl, ExternalSignRsaPriv, RoughEstimateGasFlag, - RotatorBufferFlag, - StakingEventStoreFileFlag, - EventIndexStepFlag, LeveldbPathNameFlag, BlockNotIncreasedThreshold, diff --git a/tx-submitter/iface/client.go b/tx-submitter/iface/client.go index 2081355db..e6b654f9e 100644 --- a/tx-submitter/iface/client.go +++ b/tx-submitter/iface/client.go @@ -259,8 +259,8 @@ func (c *L2Clients) GetRollupBatchByIndex(ctx context.Context, batchIndex uint64 if err != nil { return err } - if result != nil && len(result.Signatures) > 0 { - return nil + if result == nil { + return errors.New("rollup batch not found") } return nil }) diff --git a/tx-submitter/iface/rollup.go b/tx-submitter/iface/rollup.go index 9a60a64b5..36d160db7 100644 --- a/tx-submitter/iface/rollup.go +++ b/tx-submitter/iface/rollup.go @@ -12,7 +12,6 @@ import ( type IRollup interface { LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) - CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) FinalizeBatch(*bind.TransactOpts, []byte) (*types.Transaction, error) BatchInsideChallengeWindow(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) @@ -20,34 +19,16 @@ type IRollup interface { CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) FilterCommitBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupCommitBatchIterator, error) FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) } -// IL2Sequencer is the interface for the sequencer on L2 -type IL2Sequencer interface { - SequencerSetVerifyHash(opts *bind.CallOpts) ([32]byte, error) -} - -type IL2Gov interface { - RollupEpoch(opts *bind.CallOpts) (*big.Int, error) - BatchBlockInterval(opts *bind.CallOpts) (*big.Int, error) - BatchTimeout(opts *bind.CallOpts) (*big.Int, error) -} - -type IL1Staking interface { - IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) - GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) - GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) - GetStakers(opts *bind.CallOpts) ([255]common.Address, error) -} - -type IL2MessagePasser interface { - GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) +type ISubmitter interface { + IsActive(opts *bind.CallOpts, addr common.Address) (bool, error) } diff --git a/tx-submitter/metrics/metrics.go b/tx-submitter/metrics/metrics.go index 4450ac762..75e813bb7 100644 --- a/tx-submitter/metrics/metrics.go +++ b/tx-submitter/metrics/metrics.go @@ -19,7 +19,6 @@ type Metrics struct { RollupCost prometheus.Gauge FinalizeCost prometheus.Gauge CollectedL1FeeSum prometheus.Gauge - IndexerBlockProcessed prometheus.Gauge LastCommittedBatch prometheus.Gauge LastFinalizedBatch prometheus.Gauge HasPendingFinalizeBatch prometheus.Gauge @@ -62,10 +61,6 @@ func NewMetrics() *Metrics { Name: "tx_submitter_collected_l1_fee_sum", Help: "Total L1 fees collected in ETH", }), - IndexerBlockProcessed: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "tx_submitter_indexer_block_processed", - Help: "Latest block number processed by the indexer", - }), LastCommittedBatch: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "tx_submitter_last_committed_batch", Help: "Latest batch committed by the submitter", @@ -108,7 +103,6 @@ func NewMetrics() *Metrics { _ = prometheus.Register(m.RollupCost) _ = prometheus.Register(m.FinalizeCost) _ = prometheus.Register(m.CollectedL1FeeSum) - _ = prometheus.Register(m.IndexerBlockProcessed) _ = prometheus.Register(m.LastCommittedBatch) _ = prometheus.Register(m.LastFinalizedBatch) _ = prometheus.Register(m.LastCacheBatchIndex) @@ -147,11 +141,6 @@ func (m *Metrics) SetCollectedL1Fee(cost float64) { m.CollectedL1FeeSum.Set(cost) } -// SetIndexerBlockProcessed sets the indexer block processed metric -func (m *Metrics) SetIndexerBlockProcessed(blockNumber uint64) { - m.IndexerBlockProcessed.Set(float64(blockNumber)) -} - // SetLastCommittedBatch sets the last committed batch index metric func (m *Metrics) SetLastCommittedBatch(index uint64) { m.LastCommittedBatch.Set(float64(index)) @@ -229,7 +218,6 @@ func (m *Metrics) UnregisterMetrics() { prometheus.Unregister(m.RollupCost) prometheus.Unregister(m.FinalizeCost) prometheus.Unregister(m.CollectedL1FeeSum) - prometheus.Unregister(m.IndexerBlockProcessed) prometheus.Unregister(m.LastCommittedBatch) prometheus.Unregister(m.LastFinalizedBatch) prometheus.Unregister(m.HasPendingFinalizeBatch) diff --git a/tx-submitter/mock/event_storage.go b/tx-submitter/mock/event_storage.go deleted file mode 100644 index e26087720..000000000 --- a/tx-submitter/mock/event_storage.go +++ /dev/null @@ -1,26 +0,0 @@ -package mock - -import ( - "morph-l2/tx-submitter/event" -) - -// MockEventInfoStorage is a mock implementation of the EventInfoStorage -type MockEventInfoStorage struct { - event.EventInfoStorage -} - -// NewMockEventInfoStorage creates a new mock EventInfoStorage -func NewMockEventInfoStorage() *event.EventInfoStorage { - mockDB := NewMockDB() - return event.NewEventInfoStorage(mockDB) -} - -// Store implements the Store method -func (m *MockEventInfoStorage) Store() error { - return nil -} - -// Load implements the Load method -func (m *MockEventInfoStorage) Load() error { - return nil -} diff --git a/tx-submitter/mock/l1staking.go b/tx-submitter/mock/l1staking.go deleted file mode 100644 index 08939b834..000000000 --- a/tx-submitter/mock/l1staking.go +++ /dev/null @@ -1,62 +0,0 @@ -package mock - -import ( - "math/big" - - "github.com/morph-l2/go-ethereum/accounts/abi/bind" - "github.com/morph-l2/go-ethereum/common" -) - -// MockL1Staking is a mock implementation of IL1Staking -type MockL1Staking struct { - activeStakers []common.Address -} - -// NewMockL1Staking creates a new mock L1Staking instance -func NewMockL1Staking() *MockL1Staking { - return &MockL1Staking{ - activeStakers: []common.Address{}, - } -} - -// IsStaker implements IL1Staking -func (m *MockL1Staking) IsStaker(opts *bind.CallOpts, addr common.Address) (bool, error) { - for _, staker := range m.activeStakers { - if staker == addr { - return true, nil - } - } - return false, nil -} - -// GetStakersBitmap implements IL1Staking -func (m *MockL1Staking) GetStakersBitmap(opts *bind.CallOpts, _stakers []common.Address) (*big.Int, error) { - bitmap := big.NewInt(0) - for i, staker := range _stakers { - for _, activeStaker := range m.activeStakers { - if staker == activeStaker { - bitmap.SetBit(bitmap, i, 1) - } - } - } - return bitmap, nil -} - -// GetActiveStakers implements IL1Staking -func (m *MockL1Staking) GetActiveStakers(opts *bind.CallOpts) ([]common.Address, error) { - return m.activeStakers, nil -} - -// GetStakers implements IL1Staking -func (m *MockL1Staking) GetStakers(opts *bind.CallOpts) ([255]common.Address, error) { - var result [255]common.Address - for i := 0; i < len(m.activeStakers) && i < 255; i++ { - result[i] = m.activeStakers[i] - } - return result, nil -} - -// SetActiveStakers sets the active stakers for testing -func (m *MockL1Staking) SetActiveStakers(stakers []common.Address) { - m.activeStakers = stakers -} diff --git a/tx-submitter/mock/l2client.go b/tx-submitter/mock/l2client.go index d1acf1b8a..4b4c43fcd 100644 --- a/tx-submitter/mock/l2client.go +++ b/tx-submitter/mock/l2client.go @@ -3,7 +3,6 @@ package mock import ( "context" "math/big" - "time" "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" @@ -19,29 +18,18 @@ type L2ClientWrapper struct { Block *types.Block Balance *big.Int TipCap *big.Int + RollupBatch *eth.RPCRollupBatch + RollupBatchErr error reorgDepth int64 reorgCount int64 - sequencerSet []common.Address BaseFee *big.Int } func NewL2ClientWrapper() *L2ClientWrapper { - // Create mock CallContractResult for epoch update time - // Return a timestamp from 1 hour ago - timestamp := time.Now().Add(-1 * time.Hour).Unix() - result := make([]byte, 32) - big.NewInt(timestamp).FillBytes(result) - - // Create a mock sequencer set with two addresses - mockAddr1 := common.HexToAddress("0x1111111111111111111111111111111111111111") - mockAddr2 := common.HexToAddress("0x2222222222222222222222222222222222222222") - sequencerSet := []common.Address{mockAddr1, mockAddr2} - return &L2ClientWrapper{ TipCap: big.NewInt(1e9), Balance: big.NewInt(1e18), - CallContractResult: result, - sequencerSet: sequencerSet, + CallContractResult: make([]byte, 32), BaseFee: big.NewInt(1e9), } } @@ -52,31 +40,6 @@ func (l *L2ClientWrapper) CallContract(ctx context.Context, msg ethereum.CallMsg return nil, l.CallContractErr } - // If calling the sequencer set method, return the mock sequencer set - if len(msg.Data) >= 4 { - methodID := msg.Data[:4] - // Method ID for GetSequencerSet2() - if string(methodID) == "\x77\xd7\xdf\xfb" { - // Encode the sequencer set into bytes - result := make([]byte, 0) - // First 32 bytes for offset - offset := make([]byte, 32) - big.NewInt(32).FillBytes(offset) - result = append(result, offset...) - // Next 32 bytes for length - length := make([]byte, 32) - big.NewInt(int64(len(l.sequencerSet))).FillBytes(length) - result = append(result, length...) - // Then the addresses - for _, addr := range l.sequencerSet { - addrBytes := make([]byte, 32) - copy(addrBytes[12:], addr.Bytes()) - result = append(result, addrBytes...) - } - return result, nil - } - } - return l.CallContractResult, nil } @@ -197,7 +160,7 @@ func (l *L2ClientWrapper) GetBlockTraceByNumber(ctx context.Context, number *big // GetRollupBatchByIndex implements L2Client func (l *L2ClientWrapper) GetRollupBatchByIndex(ctx context.Context, batchIndex uint64) (*eth.RPCRollupBatch, error) { - return nil, nil + return l.RollupBatch, l.RollupBatchErr } // SuggestGasTipCap implements the SuggestGasTipCap method @@ -207,8 +170,3 @@ func (l *L2ClientWrapper) SuggestGasTipCap(ctx context.Context) (*big.Int, error } return big.NewInt(1e9), nil } - -// GetSequencerSet2 implements IL2Sequencer -func (m *L2ClientWrapper) GetSequencerSet2() ([]common.Address, error) { - return m.sequencerSet, nil -} diff --git a/tx-submitter/mock/rollup.go b/tx-submitter/mock/rollup.go index cf889c6a4..288019e6a 100644 --- a/tx-submitter/mock/rollup.go +++ b/tx-submitter/mock/rollup.go @@ -7,6 +7,7 @@ import ( "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" "morph-l2/bindings/bindings" ) @@ -17,7 +18,7 @@ type MockRollup struct { lastFinalizedBatchIndex *big.Int insideChallengeWindow bool batchExists bool - batchTx *types.Transaction + storedBlobHash [32]byte finalizeTx *types.Transaction } @@ -36,11 +37,6 @@ func (m *MockRollup) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, err return m.lastCommittedBatchIndex, nil } -// CommitBatch implements IRollup -func (m *MockRollup) CommitBatch(opts *bind.TransactOpts, batchDataInput bindings.IRollupBatchDataInput, batchSignatureInput bindings.IRollupBatchSignatureInput) (*types.Transaction, error) { - return m.batchTx, nil -} - // LastFinalizedBatchIndex implements IRollup func (m *MockRollup) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) { return m.lastFinalizedBatchIndex, nil @@ -68,26 +64,25 @@ func (m *MockRollup) CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) // BatchBlobVersionedHashes implements IRollup (no stored hash by default) func (m *MockRollup) BatchBlobVersionedHashes(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { - return [32]byte{}, nil + return m.storedBlobHash, nil } // BatchDataStore implements IRollup func (m *MockRollup) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }, error) { return struct { - OriginTimestamp *big.Int - FinalizeTimestamp *big.Int - BlockNumber *big.Int - SignedSequencersBitmap *big.Int + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address }{ - OriginTimestamp: big.NewInt(0), - FinalizeTimestamp: big.NewInt(0), - BlockNumber: big.NewInt(0), - SignedSequencersBitmap: big.NewInt(0), + OriginTimestamp: big.NewInt(0), + FinalizeTimestamp: big.NewInt(0), + BlockNumber: big.NewInt(0), }, nil } @@ -121,12 +116,12 @@ func (m *MockRollup) SetBatchExists(exists bool) { m.batchExists = exists } +// SetStoredBlobHash controls the value returned by BatchBlobVersionedHashes. +func (m *MockRollup) SetStoredBlobHash(hash [32]byte) { + m.storedBlobHash = hash +} + // SetFinalizeTx sets the mock value for FinalizeBatch transaction func (m *MockRollup) SetFinalizeTx(tx *types.Transaction) { m.finalizeTx = tx } - -// SetBatchTx sets the mock value for CommitBatch transaction -func (m *MockRollup) SetBatchTx(tx *types.Transaction) { - m.batchTx = tx -} diff --git a/tx-submitter/mock/submitter.go b/tx-submitter/mock/submitter.go new file mode 100644 index 000000000..1659f0471 --- /dev/null +++ b/tx-submitter/mock/submitter.go @@ -0,0 +1,34 @@ +package mock + +import ( + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" +) + +// MockSubmitter is a controllable implementation of iface.ISubmitter. +type MockSubmitter struct { + active map[common.Address]bool + err error +} + +func NewMockSubmitter() *MockSubmitter { + return &MockSubmitter{active: make(map[common.Address]bool)} +} + +func (m *MockSubmitter) IsActive(_ *bind.CallOpts, addr common.Address) (bool, error) { + if m.err != nil { + return false, m.err + } + return m.active[addr], nil +} + +func (m *MockSubmitter) SetActive(addr common.Address, active bool) { + if m.active == nil { + m.active = make(map[common.Address]bool) + } + m.active[addr] = active +} + +func (m *MockSubmitter) SetError(err error) { + m.err = err +} diff --git a/tx-submitter/params/leveldb_keys.go b/tx-submitter/params/leveldb_keys.go deleted file mode 100644 index b998e6de9..000000000 --- a/tx-submitter/params/leveldb_keys.go +++ /dev/null @@ -1,5 +0,0 @@ -package params - -const ( - EventInfoKey = "event_info" -) diff --git a/tx-submitter/services/batch_fecher.go b/tx-submitter/services/batch_fecher.go index 7c658ab81..f87b11fdc 100644 --- a/tx-submitter/services/batch_fecher.go +++ b/tx-submitter/services/batch_fecher.go @@ -27,8 +27,7 @@ func (bf *BatchFetcher) GetRollupBatchByIndex(index uint64) (*eth.RPCRollupBatch lastErr = err continue } - // Validate that batch exists and has signatures before returning - if batch != nil && len(batch.Signatures) > 0 { + if batch != nil { return batch, nil } } diff --git a/tx-submitter/services/batch_fetcher_test.go b/tx-submitter/services/batch_fetcher_test.go new file mode 100644 index 000000000..059fbe3d7 --- /dev/null +++ b/tx-submitter/services/batch_fetcher_test.go @@ -0,0 +1,20 @@ +package services + +import ( + "testing" + + "github.com/morph-l2/go-ethereum/eth" + "github.com/stretchr/testify/require" + + "morph-l2/tx-submitter/iface" + "morph-l2/tx-submitter/mock" +) + +func TestBatchFetcherAcceptsBatchWithoutSignatures(t *testing.T) { + client := mock.NewL2ClientWrapper() + client.RollupBatch = ð.RPCRollupBatch{Version: 1} + + got, err := NewBatchFetcher([]iface.L2Client{client}).GetRollupBatchByIndex(7) + require.NoError(t, err) + require.Same(t, client.RollupBatch, got) +} diff --git a/tx-submitter/services/rollup.go b/tx-submitter/services/rollup.go index 2df98cffd..ea8b762b6 100644 --- a/tx-submitter/services/rollup.go +++ b/tx-submitter/services/rollup.go @@ -30,7 +30,6 @@ import ( "morph-l2/common/blob" "morph-l2/tx-submitter/constants" "morph-l2/tx-submitter/db" - "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/l1checker" "morph-l2/tx-submitter/localpool" @@ -42,26 +41,23 @@ import ( const ( txSlotSize = 32 * 1024 txMaxSize = 4 * txSlotSize // 128KB - rotatorWait = 3 * time.Second rollupSumKey = "rollup_sum" finalizeSumKey = "finalize_sum" collectedL1FeeSumKey = "collected_l1_fee_sum" ) type Rollup struct { - ctx context.Context - metrics *metrics.Metrics - l1RpcClient *rpc.Client - L1Client iface.Client - L2Clients []iface.L2Client - Rollup iface.IRollup - Staking iface.IL1Staking - chainId *big.Int - privKey *ecdsa.PrivateKey - rollupAddr common.Address - abi *abi.ABI - // rotator - rotator *Rotator + ctx context.Context + metrics *metrics.Metrics + l1RpcClient *rpc.Client + L1Client iface.Client + L2Clients []iface.L2Client + Rollup iface.IRollup + Submitter iface.ISubmitter + chainId *big.Int + privKey *ecdsa.PrivateKey + rollupAddr common.Address + abi *abi.ABI pendingTxs *PendingTxs rollupFinalizeMu sync.Mutex externalRsaPriv *rsa.PrivateKey @@ -81,7 +77,6 @@ type Rollup struct { batchCache *batch.BatchCache batchCacheLegacy *types.BatchCacheLegacy bm *l1checker.BlockMonitor - eventInfoStorage *event.EventInfoStorage reorgDetector iface.IReorgDetector ChainConfigMap blob.ChainBlobConfigs @@ -94,17 +89,15 @@ func NewRollup( l1 iface.Client, l2Clients []iface.L2Client, rollup iface.IRollup, - staking iface.IL1Staking, + submitter iface.ISubmitter, chainId *big.Int, priKey *ecdsa.PrivateKey, rollupAddr common.Address, abi *abi.ABI, cfg utils.Config, rsaPriv *rsa.PrivateKey, - rotator *Rotator, ldb *db.Db, bm *l1checker.BlockMonitor, - eventInfoStorage *event.EventInfoStorage, l2Caller *types.L2Caller, ) *Rollup { reorgDetector := NewReorgDetector(l1) @@ -114,13 +107,12 @@ func NewRollup( l1RpcClient: l1RpcClient, L1Client: l1, Rollup: rollup, - Staking: staking, + Submitter: submitter, L2Clients: l2Clients, privKey: priKey, chainId: chainId, rollupAddr: rollupAddr, abi: abi, - rotator: rotator, cfg: cfg, signer: ethtypes.LatestSignerForChainID(chainId), externalRsaPriv: rsaPriv, @@ -130,17 +122,18 @@ func NewRollup( return cfg.BatchV2UpgradeTime > 0 && blockTimestamp >= cfg.BatchV2UpgradeTime }, cfg.MaxBlobCount, + cfg.BatchBlockInterval, + cfg.BatchTimeout, l1, &iface.L2Clients{Clients: l2Clients}, rollup, l2Caller, ldb, ), - ldb: ldb, - bm: bm, - eventInfoStorage: eventInfoStorage, - reorgDetector: reorgDetector, - ChainConfigMap: blob.ChainConfigMap, + ldb: ldb, + bm: bm, + reorgDetector: reorgDetector, + ChainConfigMap: blob.ChainConfigMap, } if !cfg.SealBatch { fetcher := NewBatchFetcher(l2Clients) @@ -326,45 +319,6 @@ func (r *Rollup) ProcessTx() error { return nil } - // Check if this submitter should process transactions - if err = r.checkSubmitterTurn(); err != nil { - if errors.Is(err, errNotMyTurn) { - // If rotator is not configured or not yet initialized, just skip this round safely. - if r.rotator == nil || r.rotator.startTime == nil || r.rotator.epoch == nil { - log.Info("Awaiting turn for transaction processing, but rotator state is not initialized", - "has_rotator", r.rotator != nil) - return nil - } - - // Get current submitter index for logging - activeSubmitter, activeIndex, rotErr := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if rotErr != nil || activeSubmitter == nil { - log.Warn("Failed to get current submitter while awaiting turn", - "error", rotErr) - return nil - } - - // Calculate rotation timing information - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - timeLeft := end - time.Now().Unix() - - // Format timestamps for human readability - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - log.Info("Awaiting turn for transaction processing", - "current_submitter", activeSubmitter.Hex(), - "submitter_index", activeIndex, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "next_rotation", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return nil - } - return err - } - // Process each transaction for _, txRecord := range txRecords { if err := r.processSingleTx(txRecord); err != nil { @@ -392,59 +346,6 @@ func (r *Rollup) detectReorgWithRetry() (bool, uint64, error) { return false, 0, lastErr } -var errNotMyTurn = errors.New("not my turn") - -func (r *Rollup) checkSubmitterTurn() error { - // If we are in priority rollup mode or rotator is not configured, always allow processing. - if r.cfg.PriorityRollup || r.rotator == nil { - return nil - } - - activeSubmitter, submitterIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if err != nil { - return fmt.Errorf("rollup: get current submitter err, %w", err) - } - - myAddress := r.WalletAddr().Hex() - activeAddress := activeSubmitter.Hex() - isMyTurn := activeAddress == myAddress - - // Calculate rotation timing information - if r.rotator.startTime == nil || r.rotator.epoch == nil { - log.Warn("rotator state not initialized, skipping submitter turn check", - "has_rotator", r.rotator != nil) - return errNotMyTurn - } - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - timeLeft := end - time.Now().Unix() - - // Format timestamps for human readability - startTimeFormatted := utils.FormatTime(big.NewInt(start)) - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - if !isMyTurn { - log.Debug("Not active submitter", - "active_submitter", activeAddress, - "index", submitterIndex, - "my_address", myAddress, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return errNotMyTurn - } - - log.Info("Active submitter status", - "index", submitterIndex, - "total_submitters", len(r.rotator.GetSubmitterSet()), - "rotation_start", startTimeFormatted, - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - return nil -} - // Handle chain reorganization (metrics + pending pool; DetectReorg only detects and updates block history). func (r *Rollup) handleReorg(depth uint64) error { r.metrics.SetReorgDepth(float64(depth)) @@ -993,84 +894,6 @@ func (r *Rollup) finalize() error { } func (r *Rollup) rollup() error { - // Get current block height - if !r.cfg.PriorityRollup { - activeSubmitter, activeIndex, err := r.rotator.CurrentSubmitter(r.L2Clients, r.Staking) - if err != nil { - return fmt.Errorf("rollup: get current submitter err, %w", err) - } - - err = r.eventInfoStorage.Load() - if err != nil { - return fmt.Errorf("failed to load storage in rollup: %w", err) - } - log.Debug("Indexer status", - "blocks_processed", r.eventInfoStorage.BlockProcessed(), - "last_event_time", r.eventInfoStorage.BlockTime()) - - // get current block number - blockNumber, err := r.L1Client.BlockNumber(context.Background()) - if err != nil { - return fmt.Errorf("failed to get block number in rollup: %w", err) - } - // set metrics - r.metrics.SetIndexerBlockProcessed(r.eventInfoStorage.BlockProcessed()) - // check if indexed block number is too old - if blockNumber > r.eventInfoStorage.BlockProcessed()+100 { - log.Info("Indexer sync required", - "module", r.GetModuleName(), - "current_block", blockNumber, - "processed_block", r.eventInfoStorage.BlockProcessed(), - "blocks_behind", blockNumber-r.eventInfoStorage.BlockProcessed()) - return nil - } - - past := (time.Now().Unix() - r.rotator.startTime.Int64()) % r.rotator.epoch.Int64() - start := time.Now().Unix() - past - end := start + r.rotator.epoch.Int64() - - // Calculate time remaining in current turn - timeLeft := end - time.Now().Unix() - myAddress := r.WalletAddr().Hex() - activeAddress := activeSubmitter.Hex() - isMyTurn := activeAddress == myAddress - totalSubmitters := len(r.rotator.GetSubmitterSet()) - - // Format timestamps for human readability - startTimeFormatted := utils.FormatTime(big.NewInt(start)) - endTimeFormatted := utils.FormatTime(big.NewInt(end)) - timeLeftFormatted := fmt.Sprintf("%dm%ds", timeLeft/60, timeLeft%60) - - log.Info("Rotation status", - "submitter_index", activeIndex, - "active_submitter", activeAddress, - "my_address", myAddress, - "total_submitters", totalSubmitters, - "is_my_turn", isMyTurn, - "rotation_start", startTimeFormatted, - "rotation_end", endTimeFormatted, - "time_remaining", timeLeftFormatted) - - if isMyTurn { - if timeLeft < r.cfg.RotatorBuffer { - bufferFormatted := fmt.Sprintf("%dm%ds", r.cfg.RotatorBuffer/60, r.cfg.RotatorBuffer%60) - log.Info("Insufficient time for rollup", - "time_remaining", timeLeftFormatted, - "buffer_required", bufferFormatted) - return nil - } - - log.Info("Starting rollup", - "submitter_index", activeIndex, - "total_submitters", totalSubmitters) - } else { - log.Info("Skipping rollup - not active submitter", - "active_index", activeIndex, - "active_submitter", activeAddress) - return nil - } - } - if pendingN := r.pendingTxs.Len(); pendingN > int(r.cfg.MaxTxsInPendingPool) { log.Info("Pending pool full", "current_size", pendingN, @@ -1115,10 +938,6 @@ func (r *Rollup) rollup() error { return nil } - signature, err := r.buildSignatureInput(rpcRollupBatch) - if err != nil { - return err - } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -1152,9 +971,9 @@ func (r *Rollup) rollup() error { // calldata encode — commitState reuses stored blob hash and must not carry blob data in tx var calldata []byte if useCommitState { - calldata, err = r.abi.Pack("commitState", rollupBatch, *signature) + calldata, err = r.abi.Pack("commitState", rollupBatch) } else { - calldata, err = r.abi.Pack("commitBatch", rollupBatch, *signature) + calldata, err = r.abi.Pack("commitBatch", rollupBatch) } if err != nil { return fmt.Errorf("pack calldata error:%v", err) @@ -1364,10 +1183,6 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC if err != nil || !exist || rpcRollupBatch == nil { return nil, true, fmt.Errorf("cannot rebuild rollup commit tx: batch %d not in cache (err=%v)", batchIndex, err) } - signature, err := r.buildSignatureInput(rpcRollupBatch) - if err != nil { - return nil, true, err - } rollupBatch := bindings.IRollupBatchDataInput{ Version: uint8(rpcRollupBatch.Version), ParentBatchHeader: rpcRollupBatch.ParentBatchHeader, @@ -1379,7 +1194,7 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC } if stored != ([32]byte{}) { - calldata, err := r.abi.Pack("commitState", rollupBatch, *signature) + calldata, err := r.abi.Pack("commitState", rollupBatch) if err != nil { return nil, true, err } @@ -1394,7 +1209,7 @@ func (r *Rollup) tryRebuildRollupCommitTx(tx *ethtypes.Transaction, tip, gasFeeC return newTx, true, nil } - calldata, err := r.abi.Pack("commitBatch", rollupBatch, *signature) + calldata, err := r.abi.Pack("commitBatch", rollupBatch) if err != nil { return nil, true, err } @@ -1428,15 +1243,6 @@ func (r *Rollup) logTxInfo(tx *ethtypes.Transaction, batchIndex uint64) { ) } -func (r *Rollup) buildSignatureInput(batch *eth.RPCRollupBatch) (*bindings.IRollupBatchSignatureInput, error) { - sigData := bindings.IRollupBatchSignatureInput{ - SignedSequencersBitmap: common.Big0, - SequencerSets: batch.CurrentSequencerSetBytes, - Signature: []byte("0x"), - } - return &sigData, nil -} - func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Header, error) { head, err := r.L1Client.HeaderByNumber(context.Background(), nil) if err != nil { @@ -1498,37 +1304,13 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Head // PreCheck is run before the submitter to check whether the submitter can be started func (r *Rollup) PreCheck() error { - - // debug stakers - stakers, err := r.Staking.GetStakers(nil) - if err != nil { - log.Debug("get stakers error", "err", err) - } else { - log.Debug("stakers", "len", len(stakers)) - for _, s := range stakers { - log.Debug("staker", "addr", s.Hex()) - } - } - // debug active stakers - activeStakers, err := r.Staking.GetActiveStakers(nil) - if err != nil { - log.Debug("get active stakers error", "err", err) - } else { - log.Debug("active stakers", "len", len(activeStakers)) - for _, s := range activeStakers { - log.Debug("active staker", "addr", s.Hex()) - } - } - - isStaker, err := r.IsStaker() + isActive, err := r.Submitter.IsActive(nil, r.WalletAddr()) if err != nil { - return fmt.Errorf("check if this account is sequencer error:%v", err) + return fmt.Errorf("check Submitter activity: %w", err) } - - if !isStaker { - return fmt.Errorf("this account is not staker, can not rollup") + if !isActive { + return fmt.Errorf("wallet %s is not an active submitter", r.WalletAddr()) } - return nil } @@ -1552,7 +1334,7 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll log.Warn("failed to get batch", "error", err) continue } - if batch != nil && len(batch.Signatures) > 0 { + if batch != nil { return batch, nil } } @@ -1560,100 +1342,6 @@ func GetRollupBatchByIndex(index uint64, clients []iface.L2Client) (*eth.RPCRoll return nil, nil } -// query sequencer set from sequencer contract on l2 -func QuerySequencerSet(addr common.Address, clients []iface.L2Client) ([]common.Address, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query sequencer set") - } - for _, client := range clients { - // l2 sequencer - l2Seqencer, err := bindings.NewSequencer(addr, client) - if err != nil { - log.Warn("failed to connect to sequencer", "error", err) - continue - } - // get sequencer set - seqSet, err := l2Seqencer.GetSequencerSet2(nil) - if err != nil { - log.Warn("failed to get sequencer set", "error", err) - continue - } - return seqSet, nil - } - return nil, fmt.Errorf("no sequencer set found after querying all clients") -} - -// query epoch from gov contract on l2 -func GetEpoch(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query epoch") - } - for _, client := range clients { - // l2 gov - l2Gov, err := bindings.NewGov(addr, client) - if err != nil { - log.Warn("failed to connect to gov", "error", err) - continue - } - // get epoch - epoch, err := l2Gov.RollupEpoch(nil) - if err != nil { - log.Warn("failed to get epoch", "error", err) - continue - } - return epoch, nil - } - return nil, fmt.Errorf("no epoch found after querying all clients") -} - -// query sequencer set update time from sequencer contract on l2 -func GetSequencerSetUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query sequencer set update time") - } - for _, client := range clients { - // l2 sequencer - l2Seqencer, err := bindings.NewSequencer(addr, client) - if err != nil { - log.Warn("failed to connect to sequencer", "error", err) - continue - } - // get sequencer set update time - updateTime, err := l2Seqencer.UpdateTime(nil) - if err != nil { - log.Warn("failed to get sequencer set update time", "error", err) - continue - } - return updateTime, nil - } - return nil, fmt.Errorf("no sequencer set update time found after querying all clients") -} - -// query epoch update time from gov contract on l2 -func GetEpochUpdateTime(addr common.Address, clients []iface.L2Client) (*big.Int, error) { - if len(clients) < 1 { - return nil, fmt.Errorf("no client to query epoch update time") - } - for _, client := range clients { - // l2 gov - l2Gov, err := bindings.NewGov(addr, client) - if err != nil { - log.Warn("failed to connect to gov", "error", err) - continue - } - // get epoch update time - updateTime, err := l2Gov.RollupEpochUpdateTime(nil) - if err != nil { - log.Warn("failed to get epoch update time", "error", err) - continue - } - return updateTime, nil - - } - return nil, fmt.Errorf("no epoch update time found after querying all clients") - -} - func UpdateGasLimit(tx *ethtypes.Transaction) (*ethtypes.Transaction, error) { // add buffer to gas limit (*1.2) newGasLimit := tx.Gas() * 12 / 10 @@ -1928,15 +1616,6 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr return newTx, nil } -func (r *Rollup) IsStaker() (bool, error) { - - isStaker, err := r.Staking.IsStaker(nil, r.WalletAddr()) - if err != nil { - return false, fmt.Errorf("call IsStaker err :%v", err) - } - return isStaker, nil -} - func (r *Rollup) EstimateGas( from, to common.Address, data []byte, @@ -1977,10 +1656,6 @@ func (r *Rollup) RoughFinalizeGasEstimate() uint64 { return 500_000 } -func (r *Rollup) GetModuleName() string { - return "rollup" -} - func (r *Rollup) InitFeeMetricsSum() error { // try to init rollupFeeSum & finalizeFeeSum // read rollupFeeSum diff --git a/tx-submitter/services/rollup_commit_rebuild_test.go b/tx-submitter/services/rollup_commit_rebuild_test.go new file mode 100644 index 000000000..442ffb511 --- /dev/null +++ b/tx-submitter/services/rollup_commit_rebuild_test.go @@ -0,0 +1,72 @@ +package services + +import ( + "math/big" + "strings" + "testing" + + "github.com/morph-l2/go-ethereum/accounts/abi" + "github.com/morph-l2/go-ethereum/common" + ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/eth" + "github.com/stretchr/testify/require" + + "morph-l2/bindings/bindings" +) + +const submitterRollupCommitABI = `[ + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"}],"name":"commitBatch","outputs":[],"stateMutability":"payable","type":"function"}, + {"inputs":[{"components":[{"name":"version","type":"uint8"},{"name":"parentBatchHeader","type":"bytes"},{"name":"lastBlockNumber","type":"uint64"},{"name":"numL1Messages","type":"uint16"},{"name":"prevStateRoot","type":"bytes32"},{"name":"postStateRoot","type":"bytes32"},{"name":"withdrawalRoot","type":"bytes32"}],"name":"batchDataInput","type":"tuple"}],"name":"commitState","outputs":[],"stateMutability":"nonpayable","type":"function"} +]` + +func TestPendingCommitRebuildSwitchesOnStoredBlobHash(t *testing.T) { + r, _, _, rollupContract := setupTestRollup(t) + targetABI, err := abi.JSON(strings.NewReader(submitterRollupCommitABI)) + require.NoError(t, err) + r.abi = &targetABI + + parentHeader := make([]byte, 9) // parent batch index is zero, so the target is batch 1 + batch := ð.RPCRollupBatch{ + Version: 1, + ParentBatchHeader: parentHeader, + LastBlockNumber: 10, + } + r.batchCacheLegacy.Set(1, batch) + batchInput := bindings.IRollupBatchDataInput{ + Version: uint8(batch.Version), + ParentBatchHeader: batch.ParentBatchHeader, + LastBlockNumber: batch.LastBlockNumber, + } + tip := big.NewInt(1) + feeCap := big.NewInt(2) + blobFeeCap := big.NewInt(3) + head := ðtypes.Header{} + + commitBatchData, err := targetABI.Pack("commitBatch", batchInput) + require.NoError(t, err) + commitBatchTx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ChainID: r.chainId, Nonce: 4, Gas: 100_000, Data: commitBatchData}) + rollupContract.SetStoredBlobHash(common.HexToHash("0x1234")) + + rebuilt, handled, err := r.tryRebuildRollupCommitTx(commitBatchTx, tip, feeCap, blobFeeCap, head) + require.NoError(t, err) + require.True(t, handled) + require.Equal(t, targetABI.Methods["commitState"].ID, rebuilt.Data()[:4]) + require.Equal(t, uint8(ethtypes.DynamicFeeTxType), rebuilt.Type()) + require.Empty(t, rebuilt.BlobHashes()) + args, err := targetABI.Methods["commitState"].Inputs.Unpack(rebuilt.Data()[4:]) + require.NoError(t, err) + require.Len(t, args, 1, "new commitState calldata has no signature tuple") + + commitStateData, err := targetABI.Pack("commitState", batchInput) + require.NoError(t, err) + commitStateTx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ChainID: r.chainId, Nonce: 4, Gas: 100_000, Data: commitStateData}) + rollupContract.SetStoredBlobHash([32]byte{}) + + rebuilt, handled, err = r.tryRebuildRollupCommitTx(commitStateTx, tip, feeCap, blobFeeCap, head) + require.NoError(t, err) + require.True(t, handled) + require.Equal(t, targetABI.Methods["commitBatch"].ID, rebuilt.Data()[:4]) + args, err = targetABI.Methods["commitBatch"].Inputs.Unpack(rebuilt.Data()[4:]) + require.NoError(t, err) + require.Len(t, args, 1, "new commitBatch calldata has no signature tuple") +} diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index 2c3bb3ed3..20781533b 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -2,11 +2,11 @@ package services import ( "context" + "errors" "math/big" "testing" "time" - "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core" ethtypes "github.com/morph-l2/go-ethereum/core/types" @@ -14,7 +14,6 @@ import ( "github.com/stretchr/testify/require" "morph-l2/bindings/bindings" - "morph-l2/tx-submitter/event" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/metrics" "morph-l2/tx-submitter/mock" @@ -42,47 +41,18 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie metrics.UnregisterMetrics() }) - // Create mock event storage - eventStorage := mock.NewMockEventInfoStorage() - err = eventStorage.Load() - require.NoError(t, err) - - // Initialize event storage with test data - eventStorage.SetBlockProcessed(1000) - eventStorage.SetBlockTime(uint64(time.Now().Unix())) - err = eventStorage.Store() - require.NoError(t, err) - - // Create mock event indexer - indexer := event.NewEventIndexer( - nil, // We don't need a real ethclient.Client for testing - big.NewInt(0), - ethereum.FilterQuery{}, - 100, - eventStorage, - ) - - // Create mock rotator - rotator := NewRotator(common.Address{}, common.Address{}, indexer) - - // Create mock L1Staking - l1Staking := mock.NewMockL1Staking() - // Set some test stakers - testStakers := []common.Address{ - common.HexToAddress("0x1111111111111111111111111111111111111111"), - common.HexToAddress("0x2222222222222222222222222222222222222222"), - } - l1Staking.SetActiveStakers(testStakers) + submitter := mock.NewMockSubmitter() + submitter.SetActive(crypto.PubkeyToAddress(privateKey.PublicKey), true) // Create rollup config defaultCfg := utils.Config{ - MaxTip: 10e9, - MaxBaseFee: 100e9, - MinTip: 1e9, - TipFeeBump: 100, - TxTimeout: 10 * time.Second, - PriorityRollup: true, - MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) + MaxTip: 10e9, + MaxBaseFee: 100e9, + MinTip: 1e9, + TipFeeBump: 100, + TxTimeout: 10 * time.Second, + MaxBlobCount: 6, // required by batch.NewBatchCache (must be > 0) + BatchBlockInterval: 100, } // Create mock journal @@ -104,17 +74,15 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie l1Mock, []iface.L2Client{l2Mock}, mockRollup, - l1Staking, + submitter, big.NewInt(1), privateKey, common.Address{}, rollupAbi, defaultCfg, nil, - rotator, nil, nil, - eventStorage, nil, ) @@ -129,6 +97,18 @@ func setupTestRollup(t *testing.T) (*Rollup, *mock.L1ClientWrapper, *mock.L2Clie return rollup, l1Mock, l2Mock, mockRollup } +func TestPreCheckUsesSubmitterActivity(t *testing.T) { + r, _, _, _ := setupTestRollup(t) + submitter := r.Submitter.(*mock.MockSubmitter) + + require.NoError(t, r.PreCheck()) + submitter.SetActive(r.WalletAddr(), false) + require.ErrorContains(t, r.PreCheck(), "not an active submitter") + + submitter.SetError(errors.New("rpc unavailable")) + require.ErrorContains(t, r.PreCheck(), "check Submitter activity") +} + // TestHandleDiscardedTx tests the handling of discarded transactions func TestHandleDiscardedTx(t *testing.T) { r, l1Mock, _, _ := setupTestRollup(t) diff --git a/tx-submitter/services/rollup_test.go b/tx-submitter/services/rollup_test.go index 79fe4fcd3..51a3f3cde 100644 --- a/tx-submitter/services/rollup_test.go +++ b/tx-submitter/services/rollup_test.go @@ -376,7 +376,6 @@ func TestTxStateTransition(t *testing.T) { // Create rollup instance rollup, l1Mock, _, _ := setupTestRollup(t) - rollup.cfg.PriorityRollup = true // Test transaction state transitions t.Run("Transaction State Flow", func(t *testing.T) { diff --git a/tx-submitter/services/rotator.go b/tx-submitter/services/rotator.go deleted file mode 100644 index bb5bb81af..000000000 --- a/tx-submitter/services/rotator.go +++ /dev/null @@ -1,158 +0,0 @@ -package services - -import ( - "errors" - "fmt" - "math/big" - "sync" - "time" - - "morph-l2/tx-submitter/event" - "morph-l2/tx-submitter/iface" - "morph-l2/tx-submitter/utils" - - "github.com/morph-l2/go-ethereum/common" - "github.com/morph-l2/go-ethereum/log" -) - -type Rotator struct { - // used to record the start time of rotation - // updated when the sequencerSet, stakingSet or epoch is updated - startTime *big.Int // timestamp - submitterSet []common.Address - sequencerSet []common.Address - epoch *big.Int // epoch for rotation - mu sync.Mutex // lock - l2SequencerAddr common.Address - l2GovAddr common.Address - indexer *event.EventIndexer -} - -func NewRotator(l2SeqencerAddr, l2GovAddr common.Address, indexer *event.EventIndexer) *Rotator { - return &Rotator{ - l2SequencerAddr: l2SeqencerAddr, - l2GovAddr: l2GovAddr, - indexer: indexer, - } -} - -func (r *Rotator) StartEventIndexer() { - go r.indexer.Index() -} - -// UpdateState updates the state of the rotator -// updated by event listener in the future -func (r *Rotator) UpdateState(clients []iface.L2Client, l1Staking iface.IL1Staking) error { - - epochUpdateTime, err := GetEpochUpdateTime(r.l2GovAddr, clients) - if err != nil { - log.Error("failed to get epoch update time", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to get epoch update time: %w", err) - } - // sequencer set update time - sequcerUpdateTime, err := GetSequencerSetUpdateTime(r.l2SequencerAddr, clients) - if err != nil { - log.Error("failed to get sequencer set update time", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to get sequencer set update time: %w", err) - } - - storage := r.indexer.GetStorage() - err = storage.Load() - if err != nil { - log.Error("failed to load storage", "err", err) - return fmt.Errorf("GetCurrentSubmitter: failed to load storage: %w", err) - } - // if index not complete - if storage.BlockProcessed() == 0 { - return errors.New("wait event index service to complete") - } - - r.startTime = utils.MaxOfThreeBig(epochUpdateTime, sequcerUpdateTime, big.NewInt(int64(storage.BlockTime()))) - - // get current sequencer set - seqSet, err := QuerySequencerSet(r.l2SequencerAddr, clients) - if err != nil { - log.Error("failed to get sequencer set", "err", err) - return fmt.Errorf("UpdateState: failed to get sequencer set: %w", err) - } - r.SetSequencerSet(seqSet) - // get current epoch - epoch, err := GetEpoch(r.l2GovAddr, clients) - if err != nil { - log.Error("failed to get epoch", "err", err) - return err - } - r.epoch = epoch - - // get l1staking active staker set - stakers, err := l1Staking.GetActiveStakers(nil) - if err != nil { - log.Error("failed to get active stakers", "err", err) - return fmt.Errorf("UpdateState: failed to get active stakers: %w", err) - } - submitterSet := utils.IntersectionOfAddresses(r.GetSequencerSet(), stakers) - r.SetSubmitterSet(submitterSet) - // rotator info - log.Info( - "rotator state updated", - "epoch", r.epoch, - "start_time", utils.FormatTime(r.startTime), - "start_timestamp", r.startTime, - "epoch_update_time", utils.FormatTime(epochUpdateTime), - "epoch_update_timestamp", epochUpdateTime, - "seq_update_time", utils.FormatTime(sequcerUpdateTime), - "seq_update_timestamp", sequcerUpdateTime, - "indexed_latest_block", storage.BlockProcessed(), - "indexed_event_time", utils.FormatTime(big.NewInt(int64(storage.BlockTime()))), - "indexed_event_timestamp", storage.BlockTime(), - ) - - return nil -} - -// GetCurrentSubmitter returns the current sequencer that should be submitting -func (r *Rotator) CurrentSubmitter(clients []iface.L2Client, l1Staking iface.IL1Staking) (*common.Address, int64, error) { - - err := r.UpdateState(clients, l1Staking) - if err != nil { - return nil, 0, fmt.Errorf("update state err: %w", err) - } - - if len(r.GetSubmitterSet()) == 0 { - return nil, 0, fmt.Errorf("GetCurrentSubmitter: sequencer set is empty") - } - - if r.epoch.Int64() == 0 { - return nil, 0, fmt.Errorf("GetCurrentSubmitter: epoch is 0") - } - - sec := time.Now().Unix() - r.startTime.Int64() - seqIdx := sec / r.epoch.Int64() % int64(len(r.GetSequencerSet())) - - return &r.GetSubmitterSet()[seqIdx], seqIdx, nil - -} - -func (r *Rotator) SetSubmitterSet(newSet []common.Address) { - r.mu.Lock() - defer r.mu.Unlock() - r.submitterSet = newSet -} -func (r *Rotator) GetSubmitterSet() []common.Address { - r.mu.Lock() - defer r.mu.Unlock() - return r.submitterSet -} - -func (r *Rotator) SetSequencerSet(newSet []common.Address) { - r.mu.Lock() - defer r.mu.Unlock() - r.sequencerSet = newSet -} - -func (r *Rotator) GetSequencerSet() []common.Address { - r.mu.Lock() - defer r.mu.Unlock() - return r.sequencerSet - -} diff --git a/tx-submitter/types/batch_cache.go b/tx-submitter/types/batch_cache.go index 7ebe49b81..fd1cbe5c0 100644 --- a/tx-submitter/types/batch_cache.go +++ b/tx-submitter/types/batch_cache.go @@ -45,21 +45,12 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { return nil, false } - // Validate batch before caching - batch must exist and have signatures - if fetchedBatch != nil && len(fetchedBatch.Signatures) > 0 { - // Store valid batch in cache for future use + if fetchedBatch != nil { b.m.Lock() b.batchCache[batchIndex] = fetchedBatch b.m.Unlock() return fetchedBatch, true - } else if fetchedBatch != nil { - // Batch exists but doesn't have signatures, don't cache it - log.Debug("Batch validation failed - no signatures", - "batch_index", batchIndex, - "found", fetchedBatch != nil, - "has_signatures", len(fetchedBatch.Signatures) > 0) - return fetchedBatch, true } } @@ -67,12 +58,8 @@ func (b *BatchCacheLegacy) Get(batchIndex uint64) (*eth.RPCRollupBatch, bool) { } func (b *BatchCacheLegacy) Set(batchIndex uint64, batch *eth.RPCRollupBatch) { - // Validate batch before caching - batch must exist and have signatures - if batch == nil || len(batch.Signatures) == 0 { - log.Debug("Refusing to cache invalid batch", - "batch_index", batchIndex, - "exists", batch != nil, - "has_signatures", batch != nil && len(batch.Signatures) > 0) + if batch == nil { + log.Debug("Refusing to cache nil batch", "batch_index", batchIndex) return } diff --git a/tx-submitter/types/batch_cache_test.go b/tx-submitter/types/batch_cache_test.go new file mode 100644 index 000000000..8db0b19b8 --- /dev/null +++ b/tx-submitter/types/batch_cache_test.go @@ -0,0 +1,30 @@ +package types + +import ( + "testing" + + "github.com/morph-l2/go-ethereum/eth" + "github.com/stretchr/testify/require" +) + +type fixedBatchFetcher struct { + batch *eth.RPCRollupBatch +} + +func (f fixedBatchFetcher) GetRollupBatchByIndex(uint64) (*eth.RPCRollupBatch, error) { + return f.batch, nil +} + +func TestBatchCacheLegacyCachesBatchWithoutSignatures(t *testing.T) { + want := ð.RPCRollupBatch{Version: 1} + cache := NewBatchCacheLegacy(fixedBatchFetcher{batch: want}) + + got, ok := cache.Get(3) + require.True(t, ok) + require.Same(t, want, got) + + cache.fetcher = nil + got, ok = cache.Get(3) + require.True(t, ok) + require.Same(t, want, got) +} diff --git a/tx-submitter/types/l2Caller.go b/tx-submitter/types/l2Caller.go index e3a9311d2..dcbe06e19 100644 --- a/tx-submitter/types/l2Caller.go +++ b/tx-submitter/types/l2Caller.go @@ -7,7 +7,7 @@ import ( "morph-l2/tx-submitter/iface" ) -// L2Caller reads L2 gov / sequencer state for batch assembly (see batch.L2Gov). +// L2Caller reads the L2 withdrawal tree root for batch assembly (see batch.L2Gov). type L2Caller = batch.L2Gov // NewL2Caller builds an L2Caller backed by the given L2 RPC clients. diff --git a/tx-submitter/utils/config.go b/tx-submitter/utils/config.go index 4e9269f95..251b429d8 100644 --- a/tx-submitter/utils/config.go +++ b/tx-submitter/utils/config.go @@ -1,6 +1,7 @@ package utils import ( + "fmt" "time" "github.com/urfave/cli" @@ -28,8 +29,12 @@ type Config struct { // RollupAddress is the Rollup contract address. RollupAddress string - // StakingAddress - L1StakingAddress string + // SubmitterAddress is the Submitter contract address. + SubmitterAddress string + // BatchBlockInterval and BatchTimeout are explicit batch sealing triggers. + // A zero value disables the corresponding trigger, but not both. + BatchBlockInterval uint64 + BatchTimeout uint64 // PollInterval is the delay between querying L2 for more transaction // and creating a new batch. @@ -46,18 +51,11 @@ type Config struct { // finalize // if start finalize Finalize bool - // L2 contract - L2SequencerAddress string - L2GovAddress string - // metrics MetricsServerEnable bool MetricsHostname string MetricsPort uint64 - // decentralized - PriorityRollup bool - // tx fee limit TxFeeLimit uint64 @@ -99,14 +97,6 @@ type Config struct { ExternalSignRsaPriv string // rough estimate gas switch RoughEstimateGas bool - // rotator interval buffer - RotatorBuffer int64 - // listener process path - StakingEventStoreFilename string - // l1 staking deployed block number - L1StakingDeployedBlockNumber uint64 - // event indexer index step - EventIndexStep uint64 // leveldb path name LeveldbPathName string BlockNotIncreasedThreshold int64 @@ -131,18 +121,15 @@ func NewConfig(ctx *cli.Context) (Config, error) { TxTimeout: ctx.GlobalDuration(flags.TxTimeoutFlag.Name), // finalize Finalize: ctx.GlobalBool(flags.FinalizeFlag.Name), - // L1 contract - L1StakingAddress: ctx.GlobalString(flags.L1StakingAddressFlag.Name), - RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), - // L2 contract - L2SequencerAddress: ctx.GlobalString(flags.L2SequencerAddressFlag.Name), - L2GovAddress: ctx.GlobalString(flags.L2GovAddressFlag.Name), + // L1 contracts and batch sealing configuration + RollupAddress: ctx.GlobalString(flags.RollupAddressFlag.Name), + SubmitterAddress: ctx.GlobalString(flags.SubmitterAddressFlag.Name), + BatchBlockInterval: ctx.GlobalUint64(flags.BatchBlockIntervalFlag.Name), + BatchTimeout: ctx.GlobalUint64(flags.BatchTimeoutFlag.Name), // metrics MetricsServerEnable: ctx.GlobalBool(flags.MetricsServerEnable.Name), MetricsHostname: ctx.GlobalString(flags.MetricsHostname.Name), MetricsPort: ctx.GlobalUint64(flags.MetricsPort.Name), - // decentralized - PriorityRollup: ctx.GlobalBool(flags.PriorityRollupFlag.Name), // tx config TxFeeLimit: ctx.GlobalUint64(flags.TxFeeLimitFlag.Name), @@ -176,15 +163,7 @@ func NewConfig(ctx *cli.Context) (Config, error) { ExternalSignRsaPriv: ctx.GlobalString(flags.ExternalSignRsaPriv.Name), // rough estimate gas switch RoughEstimateGas: ctx.GlobalBool(flags.RoughEstimateGasFlag.Name), - // rotator interval buffer - RotatorBuffer: ctx.GlobalInt64(flags.RotatorBufferFlag.Name), - - // path - StakingEventStoreFilename: ctx.GlobalString(flags.StakingEventStoreFileFlag.Name), - // l1 staking deployed block number - L1StakingDeployedBlockNumber: ctx.GlobalUint64(flags.L1StakingDeployedBlocknumFlag.Name), - // index step - EventIndexStep: ctx.GlobalUint64(flags.EventIndexStepFlag.Name), + // leveldb path name LeveldbPathName: ctx.GlobalString(flags.LeveldbPathNameFlag.Name), // BlockNotIncreasedThreshold @@ -197,5 +176,16 @@ func NewConfig(ctx *cli.Context) (Config, error) { BatchV2UpgradeTime: ctx.GlobalUint64(flags.BatchV2UpgradeTimeFlag.Name), } + if err := validateBatchSealingConfig(cfg.BatchBlockInterval, cfg.BatchTimeout); err != nil { + return Config{}, err + } + return cfg, nil } + +func validateBatchSealingConfig(blockInterval, timeout uint64) error { + if blockInterval == 0 && timeout == 0 { + return fmt.Errorf("batch_block_interval and batch_timeout cannot both be zero") + } + return nil +} diff --git a/tx-submitter/utils/config_test.go b/tx-submitter/utils/config_test.go new file mode 100644 index 000000000..91175ff4a --- /dev/null +++ b/tx-submitter/utils/config_test.go @@ -0,0 +1,14 @@ +package utils + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateBatchSealingConfig(t *testing.T) { + require.Error(t, validateBatchSealingConfig(0, 0)) + require.NoError(t, validateBatchSealingConfig(1, 0)) + require.NoError(t, validateBatchSealingConfig(0, 1)) + require.NoError(t, validateBatchSealingConfig(1, 1)) +} diff --git a/tx-submitter/utils/utils.go b/tx-submitter/utils/utils.go index 7001e5dae..e5c177ea8 100644 --- a/tx-submitter/utils/utils.go +++ b/tx-submitter/utils/utils.go @@ -5,7 +5,6 @@ import ( "context" "encoding/binary" "fmt" - "math/big" "reflect" "regexp" "strconv" @@ -240,12 +239,3 @@ func ParseL1MessageCnt(blockContexts hexutil.Bytes) uint64 { return l1msgcnt } - -// FormatTime formats a timestamp into RFC3339 format string. -// Returns "N/A" for nil or non-positive timestamps. -func FormatTime(timestamp *big.Int) string { - if timestamp == nil || timestamp.Int64() <= 0 { - return "N/A" - } - return time.Unix(timestamp.Int64(), 0).Format(time.RFC3339) -} From 46727f31c32978cb2a497e79e78550b5266400b3 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:06:28 +0800 Subject: [PATCH 26/38] chore(devnet): configure staked batch submitter --- ops/devnet-morph/devnet/__init__.py | 19 +++++++++++++++-- ops/devnet-morph/tests/test_devnet_config.py | 22 ++++++++++++++++++++ ops/docker/.env | 5 ++++- ops/docker/docker-compose-devnet.yml | 8 +++---- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/ops/devnet-morph/devnet/__init__.py b/ops/devnet-morph/devnet/__init__.py index 020efb254..c3d659785 100644 --- a/ops/devnet-morph/devnet/__init__.py +++ b/ops/devnet-morph/devnet/__init__.py @@ -44,6 +44,12 @@ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', ), help='Private key for the L1 contract deployer/owner') +parser.add_argument('--batch-submitter-private-key', + default=os.environ.get( + 'BATCH_SUBMITTER_PRIVATE_KEY', + '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', + ), + help='Private key for the devnet batch submitter; kept separate from the block sequencer') parser.add_argument('--cluster', action="store_true", default=os.environ.get('DEVNET_CLUSTER', '').lower() in ('1', 'true', 'yes'), help='Start an HA sequencer cluster instead of making node-0 the sequencer') @@ -245,6 +251,9 @@ def devnet_deploy(paths, args): run_command([ 'npx', 'hardhat', 'initialize', '--network', 'l1', '--storagepath', paths.deployment_dir, '--concurrent', 'true' ], env={}, cwd=paths.contracts_dir) + run_command([ + 'npx', 'hardhat', 'register', '--network', 'l1', '--storagepath', paths.deployment_dir + ], env={'batchSubmitterPks': json.dumps([args.batch_submitter_private_key])}, cwd=paths.contracts_dir) # run_command([ # 'npx', 'hardhat', 'staking', '--network', 'l1', '--storagepath', paths.deployment_dir @@ -296,9 +305,12 @@ def devnet_deploy(paths, args): env_data['L1_CROSS_DOMAIN_MESSENGER'] = addresses['Proxy__L1CrossDomainMessenger'] env_data['MORPH_PORTAL'] = addresses['Proxy__L1MessageQueueWithGasPriceOracle'] env_data['MORPH_ROLLUP'] = addresses['Proxy__Rollup'] + env_data['MORPH_SUBMITTER'] = addresses['Proxy__Submitter'] + env_data['BATCH_BLOCK_INTERVAL'] = str(deploy_config['govBatchBlockInterval']) + env_data['BATCH_TIMEOUT'] = str(deploy_config['govBatchTimeout']) + env_data['BATCH_SUBMITTER_PRIVATE_KEY'] = args.batch_submitter_private_key env_data['RUST_LOG'] = rust_log_level env_data['Proxy__L1Staking'] = addresses['Proxy__L1Staking'] - env_data['MORPH_L1STAKING'] = addresses['Proxy__L1Staking'] env_data['L1_SEQUENCER_CONTRACT'] = addresses.get('Proxy__L1Sequencer', '') env_data['SEQUENCER_PRIVATE_KEY'] = args.sequencer_private_key env_data['ACTIVE_SEQUENCER_PRIVATE_KEY'] = active_sequencer_private_key @@ -318,7 +330,10 @@ def devnet_deploy(paths, args): env={ 'MORPH_PORTAL': addresses['Proxy__L1MessageQueueWithGasPriceOracle'], 'MORPH_ROLLUP': addresses['Proxy__Rollup'], - 'MORPH_L1STAKING': addresses['Proxy__L1Staking'], + 'MORPH_SUBMITTER': addresses['Proxy__Submitter'], + 'BATCH_BLOCK_INTERVAL': str(deploy_config['govBatchBlockInterval']), + 'BATCH_TIMEOUT': str(deploy_config['govBatchTimeout']), + 'BATCH_SUBMITTER_PRIVATE_KEY': args.batch_submitter_private_key, 'PWD': paths.ops_dir, 'NODE_DATA_DIR': '/data', 'GETH_DATA_DIR': '/db', diff --git a/ops/devnet-morph/tests/test_devnet_config.py b/ops/devnet-morph/tests/test_devnet_config.py index f64532279..f18ee7dc9 100644 --- a/ops/devnet-morph/tests/test_devnet_config.py +++ b/ops/devnet-morph/tests/test_devnet_config.py @@ -52,6 +52,28 @@ def test_default_compose_includes_layer1_derivation_node(self): self.assertNotIn("node-2:", compose) self.assertNotIn("morph-el-2:8545", compose) + def test_tx_submitter_uses_submitter_contract_and_explicit_batch_settings(self): + compose = (DOCKER_DIR / "docker-compose-devnet.yml").read_text() + + self.assertIn("TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER}", compose) + self.assertIn("TX_SUBMITTER_BATCH_BLOCK_INTERVAL=${BATCH_BLOCK_INTERVAL}", compose) + self.assertIn("TX_SUBMITTER_BATCH_TIMEOUT=${BATCH_TIMEOUT}", compose) + self.assertIn("TX_SUBMITTER_L1_PRIVATE_KEY=${BATCH_SUBMITTER_PRIVATE_KEY}", compose) + for removed_setting in ( + "TX_SUBMITTER_PRIORITY_ROLLUP", + "TX_SUBMITTER_L1_STAKING_ADDRESS", + "TX_SUBMITTER_L1_STAKING_DEPLOYED_BLOCKNUM", + ): + self.assertNotIn(removed_setting, compose) + + launcher = (DEVNET_PACKAGE / "devnet" / "__init__.py").read_text() + self.assertIn("addresses['Proxy__Submitter']", launcher) + self.assertIn("deploy_config['govBatchBlockInterval']", launcher) + self.assertIn("deploy_config['govBatchTimeout']", launcher) + self.assertIn("batchSubmitterPks", launcher) + self.assertIn("args.batch_submitter_private_key", launcher) + self.assertNotIn("MORPH_L1STAKING", launcher) + def test_cluster_compose_defines_ha_services(self): cluster_compose = DOCKER_DIR / "docker-compose-cluster.yml" diff --git a/ops/docker/.env b/ops/docker/.env index 670440268..96de76213 100644 --- a/ops/docker/.env +++ b/ops/docker/.env @@ -7,9 +7,12 @@ L1_BEACON_CHAIN_RPC=http://layer1-cl:4000 L1_CROSS_DOMAIN_MESSENGER=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 MORPH_PORTAL=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 MORPH_ROLLUP=0xa513e6e4b8f2a923d98304ec87f64353c4d5c853 +MORPH_SUBMITTER= +BATCH_BLOCK_INTERVAL=200 +BATCH_TIMEOUT=600 +BATCH_SUBMITTER_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d BUILD_GETH=l2-geth RUST_LOG=info Proxy__L1Staking=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 BATCH_UPGRADE_TIME=0 -MORPH_L1STAKING=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 L1_SEQUENCER_CONTRACT=0x0165878a594ca255338adfa4d48449f69242eb8f diff --git a/ops/docker/docker-compose-devnet.yml b/ops/docker/docker-compose-devnet.yml index 451cd5e16..e05d06146 100644 --- a/ops/docker/docker-compose-devnet.yml +++ b/ops/docker/docker-compose-devnet.yml @@ -247,16 +247,16 @@ services: environment: - TX_SUBMITTER_BUILD_ENV=dev - TX_SUBMITTER_L1_ETH_RPC=${L1_ETH_RPC} - - TX_SUBMITTER_L1_PRIVATE_KEY=0xd99870855d97327d20c666abc78588f1449b1fac76ed0c86c1afb9ce2db85f32 + - TX_SUBMITTER_L1_PRIVATE_KEY=${BATCH_SUBMITTER_PRIVATE_KEY} - TX_SUBMITTER_L2_ETH_RPCS=http://morph-el-0:8545,http://morph-el-1:8545 - TX_SUBMITTER_TX_TIMEOUT=60s - TX_SUBMITTER_ROLLUP_ADDRESS=${MORPH_ROLLUP:-0x6900000000000000000000000000000000000010} + - TX_SUBMITTER_SUBMITTER_ADDRESS=${MORPH_SUBMITTER} + - TX_SUBMITTER_BATCH_BLOCK_INTERVAL=${BATCH_BLOCK_INTERVAL} + - TX_SUBMITTER_BATCH_TIMEOUT=${BATCH_TIMEOUT} - TX_SUBMITTER_FINALIZE=true - - TX_SUBMITTER_PRIORITY_ROLLUP=true - TX_SUBMITTER_SEAL_BATCH=true - TX_SUBMITTER_TX_FEE_LIMIT=500000000000000000 - - TX_SUBMITTER_L1_STAKING_ADDRESS=${MORPH_L1STAKING:-0x5fc8d32690cc91d4c39d9d3abcbd16989f875707} - - TX_SUBMITTER_L1_STAKING_DEPLOYED_BLOCKNUM=0 - TX_SUBMITTER_BATCH_V2_UPGRADE_TIME=1777533291 gas-price-oracle: From 4fab3b799e51cd2692f6d55062346512b760df3e Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:14:18 +0800 Subject: [PATCH 27/38] feat(challenge): validate active proof signer --- prover/bin/challenge/src/abi/Submitter.json | 21 +++ prover/bin/challenge/src/abi/mod.rs | 5 + prover/bin/challenge/src/handler.rs | 154 +++++++++++++++++--- prover/bin/challenge/src/main.rs | 8 +- 4 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 prover/bin/challenge/src/abi/Submitter.json diff --git a/prover/bin/challenge/src/abi/Submitter.json b/prover/bin/challenge/src/abi/Submitter.json new file mode 100644 index 000000000..e487193df --- /dev/null +++ b/prover/bin/challenge/src/abi/Submitter.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "submitter", + "type": "address" + } + ], + "name": "isActive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index e905a2949..2c860562a 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -11,6 +11,11 @@ pub mod rollup_abi { abigen!(Rollup, "src/abi/Rollup.json"); } +pub mod submitter_abi { + use ethers::prelude::abigen; + abigen!(Submitter, "src/abi/Submitter.json"); +} + pub mod pre_submitter_rollup_abi { use ethers::prelude::abigen; abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index b00daa729..32d4acbe6 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,4 +1,4 @@ -use crate::abi::{decode_commit_batch, rollup_abi::Rollup}; +use crate::abi::{decode_commit_batch, rollup_abi::Rollup, submitter_abi::Submitter}; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; use crate::util::read_env_var; @@ -51,10 +51,11 @@ pub struct ChallengeHandler { l1_provider: Provider, l2_rpc: String, ext_signer: Option, + signer_address: Address, } impl ChallengeHandler { - pub async fn prepare() -> Self { + pub async fn prepare() -> eyre::Result { // Prepare parameter. let l1_rpc = var("HANDLER_L1_RPC").expect("Cannot detect L1_RPC env var"); let l2_rpc = var("HANDLER_L2_RPC").expect("Cannot detect L2_RPC env var"); @@ -73,32 +74,37 @@ impl ChallengeHandler { .unwrap() .with_chain_id(l1_provider.get_chainid().await.unwrap().as_u64()), )); + let local_signer_address = l1_signer.address(); let l1_rollup: RollupType = Rollup::new(Address::from_str(l1_rollup_address.as_str()).unwrap(), l1_signer); let use_ext_sign: bool = read_env_var("HANDLER_EXTERNAL_SIGN", false); - let ext_signer = if use_ext_sign { + let (ext_signer, signer_address) = if use_ext_sign { log::info!("Challenge handler will use external signer"); let handler_appid: String = read_parse_env("HANDLER_EXTERNAL_SIGN_APPID"); let privkey_pem: String = read_parse_env("HANDLER_EXTERNAL_SIGN_RSA_PRIV"); let sign_address: String = read_parse_env("HANDLER_EXTERNAL_SIGN_ADDRESS"); + let signer_address = Address::from_str(&sign_address).map_err(|e| anyhow!("invalid HANDLER_EXTERNAL_SIGN_ADDRESS: {}", e))?; let sign_chain: String = read_parse_env("HANDLER_EXTERNAL_SIGN_CHAIN"); let sign_url: String = read_parse_env("HANDLER_EXTERNAL_SIGN_URL"); let signer: ExternalSign = ExternalSign::new(&handler_appid, &privkey_pem, &sign_address, &sign_chain, &sign_url) .map_err(|e| anyhow!(format!("Prepare ExternalSign err: {:?}", e))) .unwrap(); - Some(signer) + (Some(signer), signer_address) } else { log::info!("Challenge handler will use local signer"); - None + (None, local_signer_address) }; - Self { + let handler = Self { l1_rollup, l1_provider, l2_rpc, ext_signer, - } + signer_address, + }; + handler.ensure_signer_is_active().await?; + Ok(handler) } pub async fn handle_challenge(&self) -> Result<(), Box> { @@ -119,13 +125,8 @@ impl ChallengeHandler { }; log::info!("Current L1 block number: {:#?}", latest); - let wallet = if let Some(signer) = &self.ext_signer { - Address::from_str(&signer.address).unwrap_or_default() - } else { - self.l1_rollup.client().address() - }; // Record wallet balance. - let balance = match l1_provider.get_balance(wallet, None).await { + let balance = match l1_provider.get_balance(self.signer_address, None).await { Ok(b) => b, Err(e) => { log::error!("handler_wallet.get_balance error: {:#?}", e); @@ -243,12 +244,29 @@ impl ChallengeHandler { async fn prove_state(&self, batch_index: u64, batch_header: Bytes, batch_proof: ProveResult, l1_rollup: &RollupType) -> bool { for _ in 0..MAX_RETRY_TIMES { sleep(Duration::from_secs(12)).await; + if let Err(e) = self.ensure_signer_is_active().await { + METRICS.verify_result.set(2); + log::error!( + "refusing to prove state because signer is not an active submitter, batch_index: {:?}, err_msg: {:#?}", + batch_index, + e + ); + return false; + } log::info!("starting prove state onchain, batch index = {:#?}", batch_index); let proof = Bytes::from(batch_proof.proof_data.clone()); let client: Arc, LocalWallet>> = self.l1_rollup.client(); let calldata = l1_rollup.prove_state(batch_header.clone(), proof).calldata(); - let result = send_transaction(self.l1_rollup.address(), calldata, &client, &self.ext_signer, &self.l1_provider).await; + let result = send_transaction( + self.l1_rollup.address(), + calldata, + &client, + &self.ext_signer, + self.signer_address, + &self.l1_provider, + ) + .await; if let Ok(tx_hash) = result { METRICS.verify_result.set(1); log::info!("prove_state success, batch_index: {:?}, tx_hash: {:#?}", batch_index, tx_hash); @@ -263,6 +281,28 @@ impl ChallengeHandler { } false } + + async fn ensure_signer_is_active(&self) -> eyre::Result<()> { + ensure_submitter_active(&self.l1_rollup, self.signer_address).await + } +} + +async fn ensure_submitter_active(l1_rollup: &Rollup, signer_address: Address) -> eyre::Result<()> { + let submitter_address = l1_rollup + .submitter_contract() + .call() + .await + .map_err(|e| anyhow!("query Rollup.submitterContract failed: {}", e))?; + let submitter = Submitter::new(submitter_address, l1_rollup.client()); + let is_active = submitter + .is_active(signer_address) + .call() + .await + .map_err(|e| anyhow!("query Submitter.isActive failed for {:?}: {}", signer_address, e))?; + if !is_active { + return Err(anyhow!("signer {:?} is not an active submitter", signer_address)); + } + Ok(()) } /** @@ -522,16 +562,13 @@ async fn send_transaction( calldata: Option, local_signer: &Arc, LocalWallet>>, ext_signer: &Option, + signer_address: Address, l2_provider: &Provider, ) -> Result> { let req = Eip1559TransactionRequest::new().data(calldata.unwrap_or_default()); let mut tx = TypedTransaction::Eip1559(req); tx.set_to(contract); - if let Some(signer) = ext_signer { - tx.set_from(Address::from_str(&signer.address).unwrap_or_default()); - } else { - tx.set_from(local_signer.address()); - } + tx.set_from(signer_address); local_signer.fill_transaction(&mut tx, None).await.map_err(|e| { let msg = contract_error(ContractError::, LocalWallet>>::from_middleware_error(e)); anyhow!("prove_state fill_transaction error: {:#?}", msg) @@ -581,3 +618,82 @@ pub fn contract_error(e: ContractError) -> String { }; error_msg } + +#[cfg(test)] +mod tests { + use super::*; + use ethers::abi::{encode, Token}; + use ethers::providers::MockProvider; + + fn mock_rollup() -> (Rollup>, MockProvider, Address, Address) { + let (provider, mock) = Provider::mocked(); + let rollup_address = Address::from_low_u64_be(1); + let submitter_address = Address::from_low_u64_be(2); + (Rollup::new(rollup_address, Arc::new(provider)), mock, rollup_address, submitter_address) + } + + fn push_call_result(mock: &MockProvider, token: Token) { + mock.push::(Bytes::from(encode(&[token]))).unwrap(); + } + + #[tokio::test] + async fn accepts_active_signer() { + let (rollup, mock, _, submitter_address) = mock_rollup(); + let signer_address = Address::from_low_u64_be(3); + + // Mock responses are consumed last-in, first-out. + push_call_result(&mock, Token::Bool(true)); + push_call_result(&mock, Token::Address(submitter_address)); + + ensure_submitter_active(&rollup, signer_address).await.unwrap(); + + mock.assert_request( + "eth_call", + [ + serde_json::to_value(rollup.submitter_contract().tx).unwrap(), + serde_json::to_value(BlockNumber::Latest).unwrap(), + ], + ) + .unwrap(); + let submitter = Submitter::new(submitter_address, rollup.client()); + mock.assert_request( + "eth_call", + [ + serde_json::to_value(submitter.is_active(signer_address).tx).unwrap(), + serde_json::to_value(BlockNumber::Latest).unwrap(), + ], + ) + .unwrap(); + } + + #[tokio::test] + async fn rejects_inactive_signer() { + let (rollup, mock, _, submitter_address) = mock_rollup(); + let signer_address = Address::from_low_u64_be(3); + push_call_result(&mock, Token::Bool(false)); + push_call_result(&mock, Token::Address(submitter_address)); + + let error = ensure_submitter_active(&rollup, signer_address).await.unwrap_err(); + + assert!(error.to_string().contains("is not an active submitter")); + } + + #[tokio::test] + async fn fails_closed_when_rollup_submitter_query_fails() { + let (rollup, _, _, _) = mock_rollup(); + + let error = ensure_submitter_active(&rollup, Address::from_low_u64_be(3)).await.unwrap_err(); + + assert!(error.to_string().contains("query Rollup.submitterContract failed")); + } + + #[tokio::test] + async fn fails_closed_when_submitter_activity_query_fails() { + let (rollup, mock, _, submitter_address) = mock_rollup(); + push_call_result(&mock, Token::Address(submitter_address)); + + let error = ensure_submitter_active(&rollup, Address::from_low_u64_be(3)).await.unwrap_err(); + + assert!(error.to_string().contains("query Submitter.isActive failed")); + } +} diff --git a/prover/bin/challenge/src/main.rs b/prover/bin/challenge/src/main.rs index f134ac403..0473cdde6 100644 --- a/prover/bin/challenge/src/main.rs +++ b/prover/bin/challenge/src/main.rs @@ -23,7 +23,13 @@ async fn main() { metric_mng().await; // Start challenge handler. - let challenge_handler = handler::ChallengeHandler::prepare().await; + let challenge_handler = match handler::ChallengeHandler::prepare().await { + Ok(handler) => handler, + Err(e) => { + log::error!("challenge handler preparation failed: {:#?}", e); + return; + } + }; match challenge_handler.handle_challenge().await { Ok(()) => (), Err(e) => { From 7056e17ef1a98f0dd4df6f5ccd52c6831ea20313 Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:16:43 +0800 Subject: [PATCH 28/38] build(prover): refresh zero-field verifier artifact Program vkey: 0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88 ELF SHA-256: f916cf05f462c08692b28a112ecc65ae7a66e7648bdedcd264648993fa666719 --- contracts/src/deploy-config/holesky.ts | 2 +- contracts/src/deploy-config/hoodi.ts | 2 +- contracts/src/deploy-config/l1.ts | 2 +- contracts/src/deploy-config/qanetl1.ts | 2 +- contracts/src/deploy-config/sepolia.ts | 2 +- contracts/src/deploy-config/testnetl1.ts | 2 +- prover/bin/client/elf/verifier-client | Bin 6896208 -> 6900720 bytes prover/bin/shadow-prove/contracts/README.md | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index 82fce91b7..c451f8240 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index 365f94604..ab7a0bf6e 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index e25eac54c..a3a50c0ff 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', // rollup contract config // initialize config finalizationPeriodSeconds: 10, diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index 6e32dbf5c..4f504a49b 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 47be72f0a..94d94cd78 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -18,7 +18,7 @@ const config = { /** * ---to---legacy property */ - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index 95c1934d2..adf9520db 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -13,7 +13,7 @@ const config = { sequencerWindowSize: 200, channelTimeout: 120, - programVkey: '0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c', + programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', rollupMinDeposit: 1, rollupProofWindow: 100, rollupGenesisBlockNumber: 0, diff --git a/prover/bin/client/elf/verifier-client b/prover/bin/client/elf/verifier-client index 0e0a8f4347b7e77de069dea1d32a3154e20b90f4..3c991ba83a6c467e8453a070441c3f0c0bcf2e07 100755 GIT binary patch delta 1974866 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

;Sug3lob<>-VxyJQNw_P95{XS@s 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

dO~v=g1ZyDi>S$atjn;YjMwU({Am;!k2jc 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 Wc&WqSk98QlNY=~-D*4QBAqCfY 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

  • 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

    >SQjjtmxebqJ**-^ zjF}obctFKP?xC$Ic|)Ktl^w*HSNOzs<#{P$H;$57*$2ZXcfO-0$Z-;86Z9W3&X4QL$$XXJSh$ZAIpl| zEb#(Sfon*uRnNGNGZLj+DdQvPi)?T%JFp~F_7U`^Y#t_Db{IsD{yfZ0Q6IziY+rz0 z`53)C)S#Fn>KGSqhx8b`&zncD9#L~did9CnUk>U|+9&FLa_~pm`iVMQ#%1M>pQ_i( z2GN{Pfddb`?`OY8DRnu@zDwwC_G>JmLq~D@vhEzSjSE8^KU4cTiURM5c81@90f^a& zxuh6jocRADyu1Rx@Qs=y+~W%lQ5Kwp+5chYfo}h=;D1B5;s47f4ckNPC%{WKJRGKA zm?ty*)^2zfoZ|IHC=2#b?dK{SQf~#4Se~fN*h!IJAT4h?DrqCq0xwezON*Zhq^(3+ zu!fa|mva|*IY+_EIf}_Bd~YU!2&aGvzerWAT*U<7kFe98j&x2pw2)d7RkGIZP zfYyC%a|5p0md%+U-VXm-O-c+t&N&gwIAPA=w@4Tc<=mb0%Ga#X>_xK(j#sIkL#J3; zd;)01gu#2~TIzCKoi9rdQrU6XcreScbym(+H4>ke5PxdkfY}b5rq-aDT5F#+8R1B7{@?hnGAFEN}Qt zxWw6$x_paz1J^ZN>U1(53?D-yzs25I@GyP+t=g}xGN(KO7j_t*Rs=>+#}iol*0Moi z_TTxPI!X2>v#mGjwZ`Lk){1&Ja+U{)HNS^$FndtVf#Fc;->ZWhcCo6)VoPEgiq*MT zu~`&*3X}TVe~@~LId(?Su~W>O@c@}WV*Du=Xv>e7Q5T$}kAGBOcg6C$?xS@-!8qj~ z)?IY;C-p_y%%c_mRbOy%N{yF815c}0VuK6n@@L>T0->s(K~WFUDu_d}G%fN~@fIpr zR-6r`%yu<}Du7J?if%I>rG>x3i)+SO+W#v&GpyCrw@$q*eq1^3F`kHRRmVJJMei#Z zxpiu0oU|O{@n<+~;Q}TfKYpsIQ@eUOt%wuT;CJ^gPJB*vb(lf;t?T2gyQTZ7_V2Xe ziR^#l9!vqS@9aHVk-vb{f6~&O=WyqG=zNO3QG+sKbxM~g|2K7%>jcZ$cPrKWhBips z)@og7?c((IcKQ^m>7A28(dX0LK8f|U@fvH^v}o+q;BhLd<@Mghw)jQtC&nEvhT~}T z`Lra|i!vX>Av(=Z|M{QlkxO>c>HonZtH3+kXVvcR841wz*gFqA-D<~X|LyQz)Kd9p7swo3j`G@gK?9n2p4e9B*84 zw-|{Ao>RMDE@b^75EBW5NV(O-(F1Q~xI(ltP%c^-SSMP^)H|P)5OZ!tdhg3P-DU~z zAZH|Q`}2;#21?7$F}!4*S5p$LC$T95t6X9{0zyIl67fK5=ik*nzB(3Q5Rq2@ z-R&^cT4J_5O}c%p=yuPJUh$z*zpIDw6nq<4OJYIH`Dgw{hyH*N3Ne~PUH-%hl{dqB zkOfZZKzlst6X@`tYCK~6zPij|3*4Wug~TqT5c02SWXJSXP96$zVMD>2{5-g^`3ftE zy9sdWT7vU#qg4}3KY$>y#UwBt!VTkSD*IdQKwbV)*SL7=t!V=1g^TLaIP0SpZP-br zf2$P&5)Yn(?2aMhA9Xl(47UMPtP+K|RN&oH7^ci%y`%Zh6S4pJg><~Y#(?()oIz4IJ;wUW#KC0uKt`wcN3vaz@ ziHXwn|GHx@^82wn_E?|eO^_mAPd{t05-26cy^`=s_KT1vtIOd!#P8TAbESYW!uHxw z3GXt{_Sd^4KjPyI4T8s-LsJx`)Co%!lcEPtzpiWZRa4nu* zb!xG$9b9E!gsZUD)jfl8Ysc*Xb=cfGUg^?Ok_>-yiITcBN>pIAxVz5@!`4bc`?Q?U zdY6`nA(O-;o_Ssh-dHjnjMBQgEIyGG(dj5K-jFD!m9|(mdQfRAZIVl36TWqx>RM?% z?KeNKrQ~SsfNXwCr=qnx+nQg%hWm+&iZke<>8-VX{S3UoHRV^&x$hY_3&ax8TqwT7 z_22jMLCDBC&h=mx)wb4lxM~=Str{wg(XNyOh&U0W-6m?bR5IEiAc8RM7SOCVAR`R_ z)wWu{1oJsmc|la6jI>vySBnQrx3tynL<~Xd*iOR|c0J{`(-7t(fePDcc%+ke=>v4I z9h2oUij37ZMTg@!rq+RYs)^Nx*g&)CLae3 zqGRo~Gp>Ey44B5ufB+vWrEiukCv4T*b?~u-I${lp7BN|e}feI^c)!@9{NyEP2IkGx|OvFw(-bq`W8Ms?? zleF4%l1WN6bAn!ow@JOyr8m znSYxzXnl%yRigPdn>(|VJZKYki~yA;2>q(ktBvtgF%C*NN@`lx8c%ftGOp>&0gc01 z!9}o3?elR__#>+IYGaGSe^K}gwqx~AIolB8b3aZugG{R^i6T#7d1xye1BOrJA=axX zcfK*t>@8Fdwv$Dd{3yCCcwF$s_{q-4Am)7e!PAZ*QE=bCj3Y;I`Sy78_U8;OJI)vf z=qBut22$Ui+O>(wd*y9vuqMDP!-7Pxa|e!1dY;zz)UI}1MW=c)9krRFGPPA04nQMp z713}EhfM82oTWEUH$7B%nU>~)km1Fs=V{Aj7&A}@hb{xo9@McH!?`4s(@SgRDB@Iy zpS4-AwF&FKwpn-3W*y6`XWf@J>kioEHaF(6V=I2v*u!QG*{s9O49=N#_IEk^?u&k? z2Pm}xDs2Syyf60%)~>em*OJ;VV-VdpFr$|c8FmZbK7A65IYoO0W{ed^+&C&r)8@w+ z=KwPpWY&+3&uRUjjBf-2>typx^IeMR!89N1TXP@+WMq6^1!H3-=T zn^PqsPholWoO;~m)H1u=Esc3_RS;)bgNavU<#~=Uy$~ENj)ho!Kl_Xe`5iDz+~DCv z1h26HZlv6&2PM<45gFImgJ&O#uw7YP#$bcVdM4CmWX4iC^rx!bD|^cL0GkgOVM_7= zhwHz+uF1dybv*Nf%D&nv*$CtQNybN_fN?|f0#Z(><8>K*V(5&CnFj+F5z%wEL3T?LxsVKORHiDixpO#JPKy8VD#R0*tff}MkJxNi6w7(p? z@Z6|&9gX`I7d+P)+I=ojJz@zD(f+~KCxTUt({B@O!&!gfIK8{g!?9E|6f>aqgBaCJD5-vNM`nJ{?vy=V&$Uqwq0;gC2JwL{D)lCPUTfY* zmJbmddr{rZx`#dtXjjM)@QE0XImXBkHQ}lfr`38Vq)yNy9Q5P}t(z>xlQlxCWR6Xz zZ`Np8kRzDjM08~2?zvNx?X$QX-z23MyHhx zg;kM!wZD~}JD$|5{XOWzae8~Q{yRMSN^W#PKQJ~auzI+vJ!f}PmfcA>y+9{%{L&af zLHK_*dB3q8ou}pEfH2(t#`cbU;EPaho+dlweV383qE`;CjcILMHO%UMCyn3rZ1 z9UZIT5aMxC$Ke;pmn+6;eWJrBI4#cbr(}&|a1YUiaT>OwSJLS5TA!5Qry?I7BCyP0 zfwgDf<%;r&NLSv)y)anBl1azMYcsD8ykX;egKeOoJ-9i`;IT=~+UyLx?p9Q!OA#VH z{I(4byUJK7 ziCCX*&EQUw9Ti-fmRfnL8JntyxSdr^U`#yyHdRZwK70i~8)_&kiMt50;uPhAgInZ_ zI|xo}n{mA72DQkaLI9jcnH&Bi!;fnsK&zpA*&-I}(}gfK}@z}lWE`f$ zj!xgI4NnSw3wi2<2y?Kj&a{Q8*@|27qIXwP?kq6ZSWa_hf!WGQ+Byq(If1x2Kl(O? z_jjtgO-o4#zT?JT70hEGS%T-Uc->AqdYd*lQ;K4ZaVy|DM{J$O0pkF+w*^={Sb}uX zXuP2^8`Fd2!R0iqUuO7C2%}PtyOZ9?ZEXo$ghSsO|E|Y6i}xTk1Z&^Ta5ksGtfRiS zYdDK8rRldrJ6Rvo{@bAfu{bN7gC(wbGjkzT%|WKLxAG3HU!sWtk}r9s&DeTKg~{)5 ziYV&V9h8gwTg+^}oq>F}(!p*6781M-Ru*d~cAwW_->V&8jF@~9M(9^I_<}1Lf4Btl z*~#jM#i=D$HQ)n>wc1nJTmG)3+^NlS@e~}c-hHQ*she;9TP&o_C!&-;#no`kGeNcy z)4_2z$YxY z8u$c{&jvp2pk)iN_O`UjCw#pq`5x_M+49oI_h`?_h}L4>tG&w=;6gUKmy>nMxQs#< zaN%_8Lag)4n0P^dBD_orC1s^|?oq&)Y)uwnNcp_s;X>Eo0?*Q{zr;=JTn@011)7!j$QSgIH#k&H(uv> z1Fj7mj0hmk<=eksiWuRNig%XWzdf)+DyQXA*2y1G(GhlS_yXc_9*o#gazDfh=es46 zdw~K)6_ltF3aeyzrPwBsqG`ngn0Q@#==1}O=-alRJc%cD6nXo}BhvP;Ald_BBm99| z*>7=9V7rGA-7ox~khxfU$KfhrO*l|Nxh7_!w*$1oWJHH-qJO6vQ|o>!iV^@>cyRZ) z1SxCzNoo6X9B*d_Ru_kxHOI&bSM%mchh!wCcc+_{ zXdPSyyu(W=UrFog;$R1Q(Yhtt8kgv=FGA{4ZIGi~v5Wb#PxSEL;<0pmiZ>_pO0jki z#1jGYgD}px=d^|sDCQuu9FvMgq3O$cLNRSwf$a&Ei~WB?$5v=gha5aY->n1~f?ye| zu(=oKrCt@Ob{Wfo2d37tzVqIEi)*w$abo@k;h#>S_7z%hS(dtn z@Eo|V$ky=C-RrgMBV}yg9IOHs<4+p6ku8KTP(J%*L0&d$31H!Oq4k@zrHJ;jo|2zo z`!?lN^9*(?jEC%C9Ed?9K|4bKsGNk-P=_rVT+@@;msCi}&uVMB@egzUQ_j9q+{$;8 zp%6WMgF^t#quOURIJ@yNIyZFsS*^3fv5vK`E2TZJ-6ta9F~jm>I`}->w)?1Zt9H#e zgKK~}_R)Z;7(29QSj@u7-Il8EmK77$soNy(nP9HGrvKl+K{d zTQP4M2&?x3W69;Dz5o$7WnmNb1+6Ede)3)G>*&x+5E7GpV5di|(c+>K ztd;Os(lEQi_r<{RJ!_h|g2wNHR2WMu4`vNiJ$a1Gz?1f7%v1LF6ZZEe`+I}^jduZG zML)-KCSfXm6*Tb==^ip))e;iUeL)OkN%(t63mlIaGo;UH>#NYO;aD2KTN~0jnGdRm zFu^rW8!At`K*^m_J@npgZKy0Ar`XrDs}hVafT{7IQ*_qnRPY*BBST@jUh314UU^L$ zkPsMSPtlkf=fV4xWBiFC_h{E<1~q$%Zjxtw={1*0-d8rWUH-p3V?nmlSx1F?v`6&7 z75|1ej{@#&@s4HEiBjd42!z(hy_(1JV z$!{{*;v}7;+BWbx|IwMAO!MBvkQlilgqWsyM1liL33SN9F0jPkE5NyVRQei+>l{|( z&hS2}c?;76ym)fs($hLeZjAKs44k+i;wl6hUWBX;2~QJKT0G6$rxn^*zlDPkgjU%~ z`R?@ic995HiijtoI5wAZ_d{b~RbRRv6JKC688PYctvT-CCNv50xAtR8Gh9W-_iHI} zK{yjPt^R|4ClXVV=A(E6yJETU_-&}#=U z)CC-ZITf@^w^@J=cwpe5 zl<}a=d*A^V2DlcKy$2q^nF&1TY9rL?^m}M~pbuGKOlyuS*bAN?cq{l2YjY;$Gos-+ zfwp(*+{Gb_3d8BmE3}SM%^@&B)RimZE5!0H?-+`CUqkFpGlSNhOG^_VI9xVP<|N=X zE$D(vp{ftCjEfGp_rzme?NZ#d^+W7maAbIeyb%%+A8MghgXd}VN7_^y0BWZJ)uB-B zM+{Z)TN~AJI(E1L6&{LcfZP@`|D#<47jP~!hehmIPOODz?C!t?@v+v{$s`2@!myb5cZs6yiPEu;>g zVwzBHpo^bEr~{)BpHS-)7Z?S_z+~A;f|O3I9~0@VquQg62WjGGP>10GWPZl_q(804 zZ%V)q3L~&{4T~QU3hN{5a_WQG=u5<+{!B}VL+I~jxUGoF&$WJi0>0+S#wC~t*wrs% zR?s^*JB(xpmiExPuSpwN=&sMT%!FW);FQu0h@u4D)<0x@j+IJKrVd}QqbkN53n8Aq zK<6Zyqo$QIiSSD-^m!*VJblbVD3=hvNOvw@d3f5rHGo=U&g5;GB=iSwYotg*%0cOx45 zWUVKSFW1MiUnrZgq1vytbC^T92uF&GbiC_uzIy5#?Txs=yFi5@cP5f}I<91teut(C zsaZ{@zSU-DS~sI_oNjig8nqD~5eTX;`sLH+g{8YF_oUXN(^&U1Fa}Hk@9WS^EO7V? z=b}9)P^a>Ii()skI{V1VowVmWRA&zUzpD%2IHW19RvxP^J<;s{f7fUI7%Drdb+?;u z?GVkcb29B(NFRT%J>~d_7XARc3kUqMrNM4RfE_LmpHd&}-ZS$9h}6tzc=lk?&5eRG%6~X5sgH@X_PwAH z?kK!W$%N)*o>m&m7!R^CJ;!mt19{B>zh`bkHgdBBd#?^RsJ@js)?~%OY8pC=(wUv_ z-21P`45u-xYG^UrRO|)&8pox_*~l^G)9EwX`{F~ILDp~DJ+e7T_+as&HNKf?!V8(> zgbxv!}~CG zd;~k%{m*Ir;}8Jcsqz6L&LoWPwCtSrP+ahKA>i{|#L<~U#QfL)ytYyf=F`#gw9EuH zu!ECY0A>lmPQPmp$blPZ>)NzDQLnU#qAJo-cq!%T=B1?W)a!y45Y4ja|7_NAK3ei= z?FB78P8ov1tiUw0>BFRUydq6^a*_s8$4dKu==9vmw1jAu4!vGCF&yP zX@jWeUm9Y~l1598stP^zaJdDvR;uqSpE@OC?;rO}d0;NuGT$g?2( zA6?Qq#VLoI*C}o0jjd>}*R!x&#Xx<2Twrel_iDISxue3;cgxDFROrzA#3?&lpjjb! z_K`ye&z`4TS+D0Au5PlJR)S}H=%B0*hznLV6zA#YeCiOP+x#+qY*ND9Muic2W?Z1M zc?n}K?TXO*$bm=jKB?Zv8GyI&*Y$i^4Gs7+=aC$Kka8n+c%ZRoKKIEid~0ZHr2ezZ zwU1p`FTS3tV)S%5Jc7r)3jGkH7e&rCfA^ewpS@#pnDC2zlP5gq@!ju0J96@!jZJuu z#OWRQiqos^kMj2YILf17KO{R`PA55hu7Dr@CVh|Zod>Q1d^F&r0UrbS7!S5{$|Fal zQEht=XE6>NpU~O%`aQDo1I>xkyL(0AA+KxgWp3qcCfgQ*Us4WV<62B#v1My zS6&Omk`-%uo@q{))&Y(dvBpBS^zo!YVJm4{yfvF~P|4wOD9KNa>*2>yp<7QJ6!_As zK5xSqbDP6RHwv8AJU5=1DIORZQ`~=9j7NctDn~x^s#}TT^=|Z=TklXb;}fs?Y(1V? zE%01pGmgj{5S`Ta+JVm!FC9v2gri`JQ&OrA z04}N#P8#1F&KgJ=@p^hv_FG={g?h&0aJL!bb7&5OQQq*@)Wew9HHR_!;s_NmM{q;5 zfvM2oP4P%7osHM~B&F@}*3`q8!<)lk_tQwwQ?AP1=2f4w=`pd;YKq6`A$TJNynV;C z6ATT!$lAzuLcyyzo>l?}@nzxPLR%B`C*T~K+8l}5iY9i{6Xp0aTG&zFU1TIQ&zJtP zJD{Vx4J7IHn8e~&OA|d@lB$<9VOCu8a^~-%oDt7nF^hO5rgOxe($1c9Cn15^iyIqd zv};!G3R603SJ=M1H445K(tbB*~g zHRYOgn))UJCT)J>@R8sp(G&(pGz%HbxjP!`vi@lfgM-;U3?_UVhEshH{n;GG_`0&Q zo|G9s)2lX&=JU-#%r8#FC<_UEDGydp3ytio4}h1HNEu&9ZS}CrbMb z&B5P5{Hc+M;?0z2aIa8?%4!dkU_`%?e+Wtxo6~FHo1`ORBiFD?=m^)Cg9Xs=7w8kN zF$dAn6g|+6Q)KL8omAdB_)VynS8r8M=QbLcikV88^l0lJOvM+$B#jC(^lpxeG`c4PKTlhFGVrrh+f%E;Mgs4+i=|Z(pXzIb3zNZ~F0GdMEoMsj@fzKZk>+Rl$pt+*?mb42<-E z_gEUpCg6`W0T()Q-k#Be9`xy#%i*qc(5H95jC061 zGp%ha{?sT5raa5!yqrDj2u_N5PkM+tsQQ&jfomcTt-K`QjHldCZLBFa%nG_&)e-HM zvC&8l)eZD#%87iWFkd--4p|-vXkLqP6Xj!5c9N3Iz1Rc%M=ecS) zJ8!1k{`$@o6L)KxB9TCHQzX`D${3&za`74r#2X#JFnvWCmp5SQM^%^WJw2QoQpB{F zRo6N_ z+d#dy9Oy^u2I^O}E%|_7syqS#U4fhNbpv%oc;(W)o(>Jtzm+2p`+u;W?Rq+%9l7i@cKlr$NXbhPI>h3Hi$2*r@1V)V`SoCg~$ByE?~tz{UAE@n7?Na&KT?0 z6HezZ9u&d8wZe=xH(O7x#7wa68~l?5 zv^A5Ap}OC(42QJIRH|Jb?F3_12HvOjPxw1|Ib*C$xT2uRt)&yIl)8u=%-2bY@Sp)0 z77(B({Qd3L`~h7PWw*vb>M+(CnT#j>U0tGy4k{R?Ydv_=jC~P-Gi*ET1kir##@z1# zeei~RjYPFq(4HqjXT-0U%8MiBQ*xDmwP==Q;KfpOTRv+ew!)5A`B&P#dj%D2L|1c8 z7=38ZMt{%CcmNtfOB*QsEnj+=FFQrSrT$}3GXA~4TUJZh=~ zt^MxAQsp~#nD41ztqm-)TYIs5!MS!P)+*SEQW(D_N>Mp1IdKomSmnuME1bYxA}_ocd9r;+YlX-Q&a=zi z+n8sS@HrK&p(>^+5Vn@#Rsxg7wie#1<0hPx#q-^!G(-U4ZP0wC3(O&*u%=k(aQzGr}FU5BdXQO;VIOcA7k*I*H)?A^7F(L(T zvc*LrPONpLSs`|jNEB*Z8Hhq^!$qPjQLvV(VGupdtg-_gF<4JEyJ5Nmc?VdYv$%Li zI84S^7)eGl^P;>{Haal}N*qhWSQ?6xfMT{YHWYq9<8=7W$J*S%%dV_h=vVHD2xrMW z*@$9(lAC1dALb%?kJCKg%sX;`K(!A~(c-p>5JTx#fiD1uP|oc#<|ml~Q}zqyBDuyT zgyS&tlbkFMJw&4?GAiD+sd$`nITdqg;Y2+p$@*G!Cgv%@m;L-&3pyM#@EUQgrHs!P z(}hD~%p|>Ew6%vRrD-c7Q>bc`KZWj`q!-G@%XE4Yv-P&p$jNAvu_<(VvJTfX>0#!b zh~48-=9oBP@V*ky4lcCU2wIGcX^0tzxe|}>@U=k?;UUO6TUsVy1K7*vtxcoj`FcW< z^jHJkqJI~2x`7w_0i&DHZDJ2@8;&8zPt_lalO9AV88y{Q#ay~DRmVo}kCfaEx;xJa z!y||QVcq=kJ;Kb&$UZ}i){?-LFa&I)(;V$qx=X}?!{1QNEqdbcim-rFj7B(XB%{6D z6<}%XDpLeTIBZH-JQg2VsdgI>*ouEUDE3)6VTg~{+2#5P^w2atOQc|C&VN7cN{XId zpCaL;^L<=I{V<__YkKU1G#k*s_SJM9QxrpL;^qx|XPa}$=r7*c&gZPXhRu_F?IKvH zv3IsdP`8y(20B6csx-Ls4 zWX{qPQo`R0R)kN1(X!ptpCYz9owO6|C^_(7s++~M_-Xdr*};Dj|f_EBAfppTm0$=esQ~OD*>mDaDbIWrNa;ZYfJnD+x?2ba}u+$z;K;mo;_2u zp26ZMoO8orn{h$G3ssn+cms;NQS8foJ9&n( z^})UyJ==M!GQ{sbpUAv{XD+i7e-yt%{~$9t(8(pxOo1DmK4E~=oq4dru}sE{`4^L4 zOfK7OkB?#ETX{iru<|?%E|=(F121u&yCR2-xeyP=sBFyK3+L)Rdzg%3>)f*{^+^fc=|S!Q=qSMBv@y#!tM*(bT9@`UlJ?qHld^Q^x+B| zWkSjK>MLbeE*IvzsOCP%JpV9mr(TOd2mi2c4NYI9Cq>H2SF~)gzDSlfRu<_v6?>vM zdx={Zc#aO-z!Sp)PrnvHjTwYcntI{@vjT7(reRBm1FIuk!1PS!%zezn zF0NtX@n1bDDeyBxkOc&+aKr#*W%(+Gh#?3prraC+)pkqg(b*-iy#+(=B)t34^E&Zy zJKB(Bx3wE@D^E9X1O3S&eMxd-x-<*$oo)Cojp^o0+OkxCT|7T)T}g9_^`7>}6`}RT zI&;!KMP{*%H#nKLwt9#5EYtsRbUq2LMFvMQBg2jRwdGE%idAO8OPi^-M8C#0GhV{n zx|8NIF+g)(ITp#5Xg$j%D2rY)&wY>=G zE>{98*@g*U+!$QuZ^WSnF0qCG=4n;T%97f!ZEbikmNdYMp4dZ&9@MXj4!As=F*BW% zT&h=en*hH1S55S)SYr3xh7cutqi~}?ic6Og{EX(@?C z@xF;zDHwd%{)fzo{uGuN^N@Zm`D) z-60|yX>m#pXMbd{TX6u6N9f~ecUSu(vLPx3e3^JBrucsBoA+-zI>PCk%eH8|eLuQaW~LCNzpunaTTfrE&2sP`VnGc8oLB=bZ} z^@na{2^Lni_eRo;3An}iaRX_b!_NIwIK`jFy4~$Ou#aNb z=mTWuZW_Ht?|GT%-1ETvj*a_-O-S^Q#fXv7Rs~ z4RO((^@PDXO28?3hNpzFYxwPCtkrvW6RkYJV$_^4mFGm|%KM^nb10Rrg}z)hF_b&a zk7rntxfJ4Q=0$!y_c-0(*~N#6RZU%H_}{;dNpWPjx}KU7i>rGyQe)J?)w{6=ITa#-5odBU%wvv=U$M4Q6fsEYJ#L7`N}L}c1B<&;ffg`iMs1G~xJRd%UtxSDf9 zHM9I1;furv@AYIo4jHr#Q{im?9X7~FxZC@?cIFVqaEuX{j4T)%m{!IYQJ1J}J!~g~ zJq-=R6$~%C-Om|cb34R**Dve=@iSy?(FY7bFC-`>FD zRJIA*D=Ob!xg&IJlO7#`D19OGZvUh8HCMpH9W56uOQ5aKu&J|*jyO-b9D)g)ZP9!|{&QvtVmU9^o5PMRzKF7SpyUJuj5M&_4#k z%!OnkB|ontoFCtB@i2BFfFsK>;KcAe*4TKt_2MG`2A9Mkbc%Wbb`Srs`h<)Z^i7UL zt6SDGIDzJ@#BSn}c2I07!~rBXU3`(P*WkVJ0J@bY;*hG>V*e1kl2|(SlK!lV^UZvd zN^2l`*ts-{{KJ{()zt_d#cl(SmT#j&MSd=IiFm6cn@OE=zJW)Jt6Os(WcfdLRg&xOR3jV|4oAP<_A=|)Q^~rjFY%1wsmPeug!O3)fW3lxz@3fHWC+3m-*8f6*W8bP9r!K;cx>Li*1F+8*N2l{)%d#0^5C1bgjyr z4xH+Kl)+St=N>kH9T-osJHhCZ(bQ|Fo_)2Di)Z*G39ZW3$kWy;3k8P*dm1V$Xja+Z zcp9uhyLvbu?^!`x8R7$Tx$d%?y@A#T{qsD$7O4()UknWH)?&CKctB}LPwU3%HF}j7r4eMludFk6vsno06%UwySUtD) zx?>)muhi%7qJgjLd)tXZSK5W1rTUiDgK^W3_2h$_x?83H;nvaHHRvbvp^d%WFqyo(Z)E*vg0kU_Bz`QtA$ zxWwN%O;!>cI)5gg<^C*pmbsvzV(kL)l#2r0M1k4-aMpUVwt1nFLv;F0DCf6dpqhsu zuD}G%{0=TL_t znx*$2$`ML<$JC01%t>>tuivnlP+$0d&e127pXOTKUZ1v9k?s68HuC$(df1=l5iGvG zLA=EGIJ)>SMj0o=oJGlH{y`ow{_0?jW2Ck-Kd-cSkipyyRSXaU>5-e#) z`Fu4z*2B`2;I|@A`5vxoTOLy4_ccV49n$Gum{t<=3OWeUW^#%HfG-YXH8g_LB2Olg~ zTsE9_nMd^c!=fT9Q+$`yfA{p{F@X&h-Bo`cX;YLzETbfN7mJ!?v#W=wG_b5WteIw~ zFBh$?-<@Wpu*$+q8Y?rBZAv%W1a+h2ZE4AL=n;sO=-ES5 z_Xu=6=)_9te#$NP=XK_q$J(=f*<+X&*W$f*oX>NByai;H`$u)gLK_?2l{TxYFlpAe zE{RIR`v2qW%j27>n!j(-rfEwlrJ)TJgtC-PmfD-7P+6{EiVH$P@IgTZ5kwK?aYY|B zx0V#d4W9^uii!%jp;iHd`&A5}BGyM#RMZMCsOVD_5Eb?P&YYX%wmiT0kABjbGiT1s zoH=vWd(Iu+FlOSf;Ksxk@2ni&j)6_sB4ZYd!&NkYOT|}ei`mMEPup7YG~TA>SZ7^F z>!|W9jOGwEBb2uSvlPw~4G*N66_sDmU2j&Ds4&WtUHFIKjTdR@-jKbyZ9Gp6dqV-TdLNrdf$bINjId6OEnL_pwq!}0 znYW$jjYSt8NKFw{_9yv^-M!~{up3wl_GTO2tRazHJAoRvSCo_(BlqSW{~Oi}zg0Av z?S00hl=*hWWBoOq^QG1mHJ->Djch)_^NzFdGs|%d0mD2g81wSJJ1TGqk7yi=Puo$k z)}5b)J@BL%%q3LtZbk8+qQCg#V_wx$3t;^2;OIXc|DWdg|3)%4pYvI=L@Ix;;s&?%9yPp& z{ir6+j8B&u-$RG0HPZg~D!P_vJN9O^IgHZ@unu3(2kQu(HiUZZtazfE0M-CLZKG-r z0}{S(MKL=T-y>j6LFMR29p0}P<<_Rsl=tyrzoO_t=KB>T{k4tCn09V4n=uhaMv-iM za8yQqhF(u)HapY)_c8KTGIXSlA5;w2C963GLkfK8!&$KmpU(bpl3fgo{fecrmKJ}2 z0WvN>+WA4np#J84DN&e4_*uuNL`mh-R?>hEE5?n}aEcb?z-6TzC3+x5pDz2(^||M} ze0exTu>>0p2c}}Q#shU8!6gl5{Yl$COlqY4K?goeYGmQGr>zkrkQ}Q0VF86p=lgO~ zMp{hg@8T_hI%?PjjVv=IA(tc)@+DrjaRv7a55RAr?2mAgW%G#33vlVItjDrDW;{;w zKSIrU{-zBdVZ$HCk`H`T(Z6`h@0dKg`69Uah=_F6%$J=oWec#IV_^!*&ut9 zS2^2XwEH^@)xBTy7r!&~J}5Qrjp_gEvtLMr&wlTqBG7CKe@ZOjvxz_BP2bBBJKjzC zf!EkCrF}o}8v7T1KQdH~=}rYdR^XH0c&kr-FZw?|`Hka~-;0h~V-Fz|*H@S0W-zpE z?Khgg1drIR`w?@S#K3stj}^tP{w6G0n+0!Z3opT=OyUXoKE$_{IIS%eG~;lFv5>Ym zSM)CCBW+k9ZjsOYld^xRn5S%PTob?Ur;1x$r#3Q6a{;zEu}>w(84yIILeItsauhEQ z`h(n;d49sm1Riv>I{G~@LNHn^R@>;g&0h>SRNspx{Zdh#8_oA`MA&QN=|Zc2sko{u z92{SX@NN`VWAOz;8=O-@(^X|eXvl$z^Fr3SKF=zs#O1HD(~J|bQqVVDet2iR^amwQ3w~Z9>l7!0M;zpez0PRTRYoyoQI=VWZ3_%k+pN#T zX^5PLr#W$_OPHCp#9w!Aw0hE=hpGAX(W-o#PS z70c1ET8f@pTt{0#(|<#cq5SAdTKpS2Q+&Kw{yUH==Pa7?J1Ry2=hCL%E543|yDKkB z+<@?uZ_DunPGsdXzOFKSx};ZypW?JSJ^Y2xRED1wydHj1=thK3l;4pF;Zawf*dXwb z@UQY)5$?~w8G*z&`5l>X3BSnj@CsFEcsEvr^8`86vsQ4!JvR&S(C8WRJ0jX!evkK@ zD(SzJ9HCJRFc0iEvMawDkdii+~@N#%agmbC`X zjcYV%?5xH+QgYA}AXTLo*p2gVLe=7g)Ctgb91geDVE$jzbI7|j{)5}$0-hN*{ZiWn z@)UhmE$C}NKN0j3K|fI}5R86DqVmS*4pl(b)5>S+zoq?up{<$4wBYZGGu+0`c;nwV zoy@n3%y;Qa@;zu?I7v||G0&jV6$6inm$~&bae8A0nVEWV4=ap?+H7g~WgK`CpW-VB zwGE-1>^0hysaLp-S7?8x-aj||mY?ao;kT&NqaWjyR)zrpZp9o**L(Dj3bhl_q$Rv5 zt6F{IbF%as@BtQ1nR@j%tBkI`Oca3&Kw~Nf+Rkmd5d-tnqD1dbiDF6h@P(TC^4#b` zB|>x|F4WYI@i%cpHzuowUygt(@FcQw^od=K?8+ido7r{s0&bq%lUCw0e7nB)Q+cjF zqS$mFou++53v>1A63;_8T$rWmEBpjb+-DN%kdJ%Czs%JWE`1p$6K%rR^M0{P@eJT^ z1XYei9df(v9N%Hq>yEWaETP?bI)3|XRxor1HjqSfv7?tKI>FT(;>N9_3F(rEU&XnU+&z$KEz#(!yldwrl+al4dC z3-#wKaA8V{EBZ8*c3$1aw%Xp69vrT`|7T`~iR^x1>W%KFJfB{2Ug9^z|4j6$SPqbe zFi_DY4z)UzspnL_@S!+diqFW{{IC?nCp*ON%#D1q<5mS2>&WP! zU*gtIriKnWF3X>mnmj2poWPgmPop74ddVr)CSQ(R@`TUt#obSjL^sTCqOLjW5@miu8(8taYvUj`=_M9@~mNdt?UjbJa8Ig!F9Wft=LlWw*MD@Ir{Y@({kXx05$s-AylVYPlU?f%XS?*oBij0H zv*dr;14nz|wYlpPn=}Gl-HX{z;_g$uB!AR5>$mLEXdiGdEj}&&Wk)@TUzAg*YDk-*%BkfCFMBDRbuN8bqKEiJ%r2dEd^GzhE=bkKxkF}SvMSm9w)bvK zMLdr*gELbm7e%b&==EdtDtBVS@~+@zJxRT~>hrvfGO|IZ)lDz*a>l4BV3n&#p^d@lC4ALQ7u2^0U;hpS_rM%#C}PU>DE&HghF#AI+$z@<+j7u#+yp@{ooR3ny-x`)?NDM* z@*xKzW;TiaaHrq=9y;!>`hpsJ=wG|7WwfcMzLpO>P49&Y({NWsFNklvO55>!k@<@4 z1O>LET!%`}vMc>1I}MZFpCWk8v_Rp_>);^0Y+S%WkEK1KJ13bhou)lUHD!8n$c)Ew zv7D|PuN7Yn!$Zk0Jb8?&%0ts%S*Dkin9tbx3Yf2aP@!7T)6`g|7mZh~1a<0Q!gF8c zbWhlsML`*Y3*J~~x^%(Tg*FbxL5x@B&!MLN za9{8sp3j=-i;#!ZPSgDTHh zB{2(E_w<8aRwb?I$KHkS(faErbdyAmJ7OtiQLaXn32_HP_P4s*=?+VpJ#Cyr0HX(6 z60Uj<9qA9HjA>-{)BQP}dFX=~3GOc)p!+9J`QN4S)xk;%M_pqSoWv#TOY_?}hl#Bs zn7E|Envfz#Er~CSB1Vmk7e5ut3f>w=)&RY@+Qe>D>tYN{xCQ4ZMr&*1l5I~6W*h5d zssS&z<)t|T^sXglILTA_e#)pP(ki68wNX-be+zN2b=jut=&}usRje|GCCO9XuT-hB z@c|wb;C$&7>pf5N0$`RB&%)-isCp=wKkcB#;iHSwezkG`OI2M|?P~ou#S1DR+&CQ0 z8mt`7{GO%_g2UlugUrEtHJ@T0JD7dL&%WjF_rA@-;ab)QHqPN%=KJhgon7tm(GhZ+ z?bx%>e6}wyXIth`X}R9dyGo|$%~Vs4lJK$Eu;cV@E<6_l#UqAwbV=H4N0($J>HbG6 zvX0pF1^MHEX~*ep`PM=R<3IV?qh+z;N6TV98*>;|;;X9c zpObQsH3SW;*)H~c))=<^QA#;G87Q5$O$Jq`ZP)!DrR=jyK`fH$Wp6LEz5N@SUxA<| z7RT+Lw^Zo$CDv{`158(om*|tk#wRpD*Q>gkAKHQ7THW&ixRWd|>e@eo(lLxYXC`?nv1tn8^Ze4)6$__Ef>?eq1nN|9Po&p$iY{Dzp4V5>c<|GYgPnCpY?ZSK75>~NBR*>_Ry+{|?8 zycWU?RsooIL=pTHTatsm5~nw0Jcm9_m}!H2xeA}|Teba6mu9B@2)LaC{sAyv?c#A^ zQYf<@?61D<8Y@8j9 zjL%#0G+a&8Gy*edV>i`|)bDfSZm#B$`lyJNYZE4`WgFnGN-I>A@~LdbiIz&M1Yprh zs#7V&RRpDA3867JOP;h+3QjAN3l-4?dl-ox1nu$dHkt#`i60inpzE5MqCb^*wDQk74@Kklf|0~ zPOHE?`otn>#6v)^{7#*kY+RnL)4hOENRp{>pA9EHFH zq4-)md^btsD;H1UMyc9TSoR(bi`FIy1h%8_e<;CgmwWj=2csiD3yA#PZejJ<3vuNIiCCF$lhfR(ir zyZ~_jSPQ<``nKV;f)R@YZ7V5xe(RLdnlEswFzYhFj>2$#3&*z>g&9u*$5kUvs)W=q zN)x_mT*R~9OrnM{`lu@FHsOVuNmr?PtBteev`$I#O1D5wb@GPFKw$?p7n zaGoz^18oiHPX_O@w7xvzaZLrzCpfPv@Jm`b5sFz~Ad!W^_M|kq2V%JAMR`C{G3$P$ zw@nvND)WE5*Efj0s-nd#Db z%?-dIF0|mc9{ff#9nzBg=Hve)zhja<(*P5}hh3FmX#2eR6z!X=pI2-=ikNZ|ZWp`8-HqQiH4!ElgPXWv^kE4CEz1~GN|Io4by&QOK<)zxjpLqO4_|+U5FhxHjqJy^ z3`cB&!9b{~Wr~T#ovNBf3KOlLz`)t2vEd|B?O4=fJE_}LK~^$P(saFT9?7bTl(j-hP6x<8xJdRU6y=ZI95M0V9%x;P%naAu7xG2rTELHTJ9+ApB1_++*s6n4H zA-5>T*{#JWQE-x}(FJhlG*hE9;I2$Bjv_p)f7m#?g=s~t;0``aF3?2n@rPtWGg3Ia z30m+nrb!lTb%?d8?W3AY5@-5+YN-JehGZ)+3XsnUqiSSqr3Ph6z|#;oIVPmqB9D78 z0828~@&ONYz-<9zLY+#_5jaiX2JO4M5B$=3EI69-Eg$ETf{kkaAABOVBbb?jNHH?A z06RS0^ngh(rcutvw>)srNWrdFFa+ShlN^$of2#J_3id=&4E_eQc4?{2zraAN!d+aLFPPEd7GA@=X)Hnp#VJ+iVfm1CA&jq6X;WSAhK+wW;!T@!js?(pr zz~KwVftG$?{G!saPo~=ak1@8A3~j(e)%hUc(25k#2sYJ!M5b~e%k6fJF%rW`p(I^* zz(3gZcAM6|11w`>(Oe2K`!X(uKgHAfTER)4);_>P!82L^);B<~5XlT*0)``Ex*(eH zSV>@8NNW$^VXRrYP=nh!$Le7!kNFv3?nE3OuW@V`C;4~{c7BBSEqH`kI}U^=*%tT| z@F>7SXa{(1-;5h&3$zRWiva0P0M9|G)eY&S>`;u}PF6Q$+HO}tG46Jrk`ZuCsiVnf z_U=q8&ef|T78L`;5b+SQgbFe6)SuZ?SKtDO)y#l+eQxFE&Ew6*~D#ai&- zk6am-tbEh5X?%*Og0U@@ zk~meUv8fdti38D1c}B{FzcMZcX0{180xo0NVWERIuFSR&Rx3c0QpVyueI4)ywPLHL z9O>W@(S8Equ`&GF5j0awO=OZ$TMKIYrp6!BmkuhDUYkrOyCFb=epwvYT9{|k*& zl{D9g@h*ti*}B;U+%9lhpgREfa0s;2rcbttTW#2OM3du&qy3vVwSpJh^eR3?Od+r( zPmLtEfruqfI%U1UDWMEzVx)yK7TNT}Z704Fd2LOTV`U4?n?s^%ZFZb_mA0L)Ut1A< z-@g`T#zI*S5`J-j_Dh^s9)Tm2Bk*~}2z*Fu_}9n*+OC9O9Ku{kSIp8UMocu0+5rg3 zL(;WjGyqr85+?^3N3_IQPk`>kmN;`AaHq7y8E8DUZs2;Oj6yrCJcd2W4lxSP*4w+y zM`+4yz22>@qNdsUpon%aGBB~j6^uH@fyoe?!BoI3kkHx2xC?Lz@J?k`_;PAb1TM{Q zy7XN)Fb?!derMo+p~2W9)dKGXvJ`|)hA}Wa1-RA>uVEbMlME-|f5kA(?{?ruuoZml z3F5!}kX0>z6os*c!ewG?aVr(f(JzV^^=SUwFdSWr7R8*Gy9V@mDR-;(Ux{@i+;c4W zXcBLp=xgK3R8xT@&KNClipChl{A1kel|Uyb81%;~gyG9|vsK4Nu(^EF}xhx*RxJh>?aNIP)^5L*A1WFKaMh z4j&F)#(dCYyx^Lu*8EigmjcPAQ!6{FfO%Ni8P0@YkYtF_l42%-Pw0%f$lI0a90Fei zTpn;vesk>gjU>NLymQMPon-WJB`b!rahrwSdp0UL*EJrQ(AU@tkIF(lV!2pQ$>H#B z&jAFlb>{-Xuba|dD}@4OEvv%niu7YSpKYOID0?n1b#$d$Z=uT<gg3drUl5KQp){dNChFfOfLQ+2%73b6z$Ba z0T+N6m+8GnnBO4noK^~do#GM2G*;1nmEwV&3Wc-w(rWOC7+<95Q%2L8QuHYv)@Q)A zGMbiPTr6cYYbE{{8lHNqa`=6}+9?8y4a^lXE$4KGN1GtfE19?ZV7wS#03Zcv7!uabbHGcH?;>#}m434{u~c}|mb6O8kg&Dk%{PE+ zWd!kps@V9H70g9oWLqIsV_SebKOMg@(&0WJ70-t048 zLz3Z@_+OZ%J3(y&aMhr5GUT&r7#T4nlB!9bUrEpJ2p%^wE(ThaPdf{+3$SBo0l!zcGTX|NZ5R)rp&k6gv?jG8 zI2~}O7|$-0QWI?$S13vJnb0b|25_r^m2n5|UebH_w{8O;R*tt`?73sm79E0ykRSFOD0^r62r)C^V zpxF^1Cj*JkyWt~()Mf$40{PN7YbJ0rfKv+wis5;{T>zXkI9o%ekzt_>Q53)Fsxgb^ zg^JEP2Md1lvEWBNpF6&Lyvx7zOI-bpFj_pD2a_lSewFz|;CM}^7YA-T^C)V#K|dqk z^O6+Oz@Pr$%4IOQo1VE|-`U?RJDQQv>u5$=PsJ#4pD?TX;}!ju1BxFmoNK7nOCr(XDjnYeOL_I36~Fq^z^@SeI)GmX@av#FJ=(0~ z^K4c0S*I(0^#eiQ0rbV7F9vcllW){7bX$99!;LtS5M4yO zZ`5z>q3t4ry;r-uabH8VF0TV7_;X;)I|A`A%3<-$BOTmt9B+&9(q{()IS zE(@K;X=gBv?YK26pS&jO$Y&uSJM&l*;ox3eVb#VbTW)4nEbW)K`6JNGmlG}I#B_o= z9-G4%G7L-+8{@ceRv;~qwM2wY(ePJ2SddP`rz*Zlp|um0&`~shlm}%8C~eG>)R;4= zy*VakOY3Ns3u)D2d~=Hleuta%XdiLp#O;1KFdTiFa*Qqa`4{n&Wz0u(H5@y>btEo@ z)h8B5bBHyq_vFPqO>R|p#(!w~4}Hqwr!CP>aJgT@gVs0eU30e`PnRL*Gox;xO*iZP z^Xr~nKk9VNe>u47o4Zi+&H96G>qNTq79EdCPbTA5obe8Krz^QxC1xtOuD(w-gDn_y z--?eZjqhptZTe+ZR;eF!HtoOg5&0n1L>}nip9TIwPmS&F53p8Bqv{WEQ^d`bce_5W z*!)=R=kaj&-r079kK*%h*L%BqC(zy=$mRmT=ze~xMYW;C+rVcje6*2XTng6@Um4%M zR3G8#5k;J=?WEd^HP0XBBR^pT?X?GZ({ zlq}pDY711E#+gIty1Q^}-U`vCyYxZ1=nj?8hpG84e6wl(NPX|dN%!c%_}IH~tlq6{ zi!WWN|LpGJc{|O;_)z6a>`ddd4`}uM`ent|4x8iBbej1#4OoQ=h^`=%=Btn19pjHP zP5Fp(E-hW9_vqnyK22}DZu5UNjl;)?J6GwKl~^zMgW!=HzMj)!9*o(PC7;KO^ZN2a ztDz;{dWy@|>G%irxLbQLe&9jGmy)`D>o3oAt^e8WTEDH(wf?n>H2)>A=ZO3bG+;Hp zbsBdtW2DQgkKXIjFVAr4qc^+saUZ+%g^vy_d`sC58PK$U_Ikw^x}HZ;pv=d8}z%prEFF+!kKCn zpk2*5ZNR*QvtMYFT|n18tJfE57(&^GlkD2L5V4d3as7ru4dcfaX_M&nI6fNECQ#<4 zmNlgEh9&RLO`P}mR(Y%Jyg^$19OoU-D*af=d&Tpdw|lF!Qaf*FI`IYl%@U)Xzl=R9 z(FnR@#iOKrtXlSc5q2>$seylSckYmv82*Kwiw<*OD#U`_{#EEp@;D-WN>6NHc|udZsRekd5xp(>XtGZ z4^iW5oW6p~2AeymNq%pkn%DI+3aw~MdTSx4m(s4+b=;@Q6>LT5@auZiFMzfnMXunh znY<^(6MD5xF~1eXrPN^yTtdjrS+sJCeo^o0=k)5?F8>(BoXSPf^;&dnkJBNeI2s zUeO!41AjLnm*s9HlZ*E4W`%f(R#{I;bcj}b$_oFYB>Ur2{a=N0D5gBd4xos>p~atZ z=1-B?iQi2_KIhCI(t^)9eMhVGx2bOv<2Sd$zh>uqi9b5(5)XW#k8qV}kNOYp=TSV? z4P72_RVm$km~Ppl|GSVs>v7_Zd#QXcMz0zBY4={eBs4m%j~?yv4}u$wxb3&~o3GK< z|FT(Izgc(bJKn|+VTVRYt9yAzg+A_OmwzzmMz*^vKHy6|?CRG1GY5|aB0(;9>ezu` zUl+V_H7)&0zt=B-Hm_x(b}{YR7$~Llzvke~b8|;dZ3Z3q8Wzz0(F%V?eDyc_Yo3V7 z?a(D_lS+hxEJ7?Z{ISAgJfKAQ74s;xYkN+lBst`3+Xj8IT3LvBuo&CKY8VxRz)2qD`H$)FzY{n z<*pkjUXFv@aGbif+{b5*L1b*1r7z@?W!r7H2QO{7I#nrvE@)=`&y z=u&XwZ4Dj=%=K+IEk29lw2bjYORMlzEn?ZxcK$~MwuMLgH*op1GYIk52~vQqEsqh! z4}3NQ1*fz(*0zj_*r!l++s&qbK;Sg}Lx8JoYfa#A`JkO4snNYL+jO#MqpAQspKSN4 zHGO4Lv~4*(q}J^P$JZSEqF*atin3MEgDQ`|!|qvFdsr{&yhaRgl>`1aV0L;(Iozv? z1syHZeA~v^MoO+=VTFpz!Q}DGoF_PE3kYaE#G|g-&xi(j5Qr6M9+8lYb3tQ38QRxT+stRTT zE{oY!P^ysTLl|UmCnViFH*=f#L9!0%#f9c7e-TDu!9*5$crp;4NBa)xRpX*@e=+c( ztc8SMOb)hS8So@rWq1(NnhprJSa=VtuXVEvQp+VPvjOWJ&n@Tasi$Z zYr#y8(MfDgOD}tut*mB^w0YsxX{nn(0Z(no%N!0I^Pg&$7x_aWlG<6E>3oMtj{ugc zkP(Wq&`{t;#}E9S;w~d|uw6(}qaPHUQs}>coeCxUafcAbv1$G(&+ZSLC~o`UH-I@lJLIzZ$iShc zU?z{*m9VLLHp&=>%(jp+ZU>wcQoc%c2+8+&w6?m|J;j$JnzC@Wr2p70Mf(&)oluZN zO7j@t*biLk>f(>3T346W*~ZyI8oL0us(Pzqt9;VK_>+XTQ|$zd=y*vX1p0U`LCSaX-gc@QGm9temnPh}gt3Q&Bh>x3dNgN40qV z=BQWgO~4$RofgXlt`#rC4g*eJS~l0egPE}v8INnpjE|okrEw^5)k7~D~q5eMujj8{g*)Q-aVt{uVIj;KAO zc&Juo`wY+HA!Nj!WhjZbt#iFOEyC@caY?V{aX8?l_I&4rGd}RRT{LyX2l?=v`&4yI zN6Iqyfo^IH_3tzZ2MIRaa8f=I6_LgrS;ysVe!*#w9JVQo%`~WIf3deE2ivqb%?daBKmGUzr>q zBCM^$EXIdGIxVnF!O6l*0_?QFa==nO4hy`8N#$f4pR~ZzSjqz6rK+GY<7E0cBk+P( z-M;!bt;`JckC?Awl}$bzm7$;V42yAKfhR+`Z!~X^aFpYLc#Kbt$V|XR0xR1^AO^-g zil3eL1@J{hIB_z4<&dYz@ij$=b8eY97u%v>?P>+5x|wSLI}2P8vl;tRQQq9Zdu!C7 z;hc&2APzuiJ+%i4{TM3Z>iSMMe`mO>U!;9Gf!^*dUMk4N@0fM*A-RDpxBE4n zjJ!a1Zw7eln{T2yc}U&-V|-~|poiPND37++AobU`uoJN8JldU))J0nQWHspPLxX zrpL>yP$wtajxO#H81A*it**wU(t#oc z;BvO@9RgtmX#aGi7?;KaMS(52e*L`ok>Wt%kX&nze;H356Wik*#|M_U+>3so)irFr z(QH!uKEl@QL~SPoI^`xt`X_VQ;UF&4U{m51QNS?e;0bKXbu?!};5>KqSlT`zfcF$u z+sT#G403EbQ})EbAU7UR8Zt3Z=G`dvUP#Y_{Roe(YGm#Me;c z*=)lvV?F4cdMH4hxBN6c?_59h|`Vl*5sgZS-uqG1$aa%x|7C$C?yWs(!R5>>n^y7fmL}T9ztuCSS>Sop@ru9){Lpsu6@fvy zR;_>5e)jeo;(f1#aBj0CKIiJdK(}`V*bZ5IBdxp!*|QCLU4E-*KYnwvv)A8vP}A2x zLvLLJk+MI>^EQF19tj@b=FoJR^Ym4mqh)EF)tgpa8(31Tb+ywvJJPz)kbj}p!X0S- zzXCTFYwc~Cdnz+Zz5wE?7LXp<~JI4BY=9Y zS1bZ7<&=Mm4@L2ICV&`H^t!ru)3QJ~(_6>T=yl5%!FZc5q`v&SV@(`Hy>tRxvz&ZG79Ufl*#}{l~1?K+c{ql*Cr~ZE@w41*RWD(71`g5juzI()X88^F?Z73)H(4KhduH0z2GWKBGtOM>m;;*Yfyx%;VII->%*#^i7jp`eM%s>!XuT zSik6?wtiz=qXj5r)3(Q{d{y8!x8^2mRiL7`JZn@C^I+CfD!~`88HnF+?m473!ylGb z^?tnL1A#r6?rqP|ku`x4{i8GZy$q<|gG5bpu0P0xo(u8%g#)i$6hD7$;1o}xQN+Y` zLEKg%8H^5OJs$Y(JpRD1wg>Fi#b)FZMwuSW3W4VVi_mKsfYle*3U&jA)U`cikXOnQ znOA1@Tbgu&=)nhb3>dfHIl6M?G2@MQlPz=yVUC;VdYaz0IYB5)4hL(7*`QR5SV z{u85aDcl=%3*%&;q{%3$3#a+A!g#t#nkp(Dg}0zFN)(OfFGb_|i^e{Q=A1Y{oVPx4 z2**ru%1Is*y)}N_lYxs|#o_N_7~|p5I=tbOg)^e^FwiV&db;H{(Y#o(YtV5oX3+GnZtF@V?COtFfF;coMNYulqnqo}z%S9e}Q=PMeN-& zo>f*KPu8TtV`$8WeLCSdP@wBLV+%N|ugs*b%!Oi>9M3(1=aI3h!+OAKq^#g5V2q4i z>aiZh9p4OZ2;l6H6n#B!7MIeLje%=y42}S74B&e~o`R_&g;LgK+ogpxE>0Dt(&r|N z@$s}xaeo+#VOh+_;Zkd3IkL9z;BB5SWw9EP&z$Y6OzNQ!vr^2XNh0k*;8bkjc%ceh zMa`vsI@11U1E)mfQ*@jjNF`43m%(Rp!k417t`1Gk0^HpJp9z?&SzT|Z7%%g+kzH!R z$!@3MjXQ-`G^sJao@(?4EaY=@< zp(HfsKYd8&IuvUPP8Rmng{n%?fuIpSQrD`yOMsI}UPMf$3S`Go%-B&>0dpA_1F>C? zeF5hI7CJ>^TnL;9Z#zjJ1t<8Fk9of5Qo^0tzmSQ5GEwIVNaTHEITW}Pv^;C?V zg_|>gV;cFg(iUjCFIN_=9o93tfkvuUT7gpdY#&xYZ1X`{rSUXjn0C$*RX|c3*}LzY zc1o)=(p#C=n4H@zf1-jH1LF$Inh>I4Iy5PXsyHS)|HZ&iZ?;dvv){MktX`mN zey9a0?f(Bu~)?+^b-afwK^+1u!JDmm7=Fx^k;Ibl5J>EFW zq;e_y-I%vP>sfw)Mm|4mctPwYl(8}DrZuc};#6w56^feO24~W$ErHYUEEtAU(WP`? zOQ0%0(NDj9o#tnSay_*)Y->^>>u@}8Ti_+w!>MP#~+~79y;$0d8yR|o{W@q54Eb~>oCIx?L(`QC};QN7qr%m%uJoLB# zj}9s{z5Q|E3Acr#6`uw=yFQ}w#(sFGR^00yYUtRz6W!X_uWvUG%oU9q{w!3gH*171 zs~KYeu$a!25WL~EKF36aC}9&-gQ(m=WUj;qM;e^e#m#|)_8>OX8nq-|jTGuOV{6Y& zkB+bl#H~h49lR_`=3!nLp{Rxz_gs|sbiei)7`Zbkyx#}sFKxQbcPm^GK2=WQ>h2=r^FVP`Vt_JUb$?&hbY;96ai@7sx#g8=z&{Xc(m)jrCQxD$CPD$yJZF zH<1f(a)=k5m&_*)qP%HxsqG<-!babu7|mh^tqQAKWEX<8rdC33j@tQ3xHgl8*$OPA z1S=Q5HmSh*Y3)Yes1l>Il8NcGIy2_2N7T-8r8K-TTH?!axnmjSN%!gO?+xZz^%2oL zyS|uzW7)W7tKr#xMP6w{I5_>{%21hCoNV)cDtIQ)$^RaE+~x`X(enGO`W?N6n*Mui zaWUgE#w%RL2K8Hq2co{f;*}?ldhNj!%lwv3+7qZMHflLy#d7gx8xIU53Rtsf#h$Na=BJMKl_p_fbOS}vn#jGla1sqEYEy4~loTzruRye#P# zNMm}GN>3RyyfZs%R?!z+56NfM{WDqS(I?Q-fxSxOUw#=F=<-S)+!@>P>%c|D#tF%1 z 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 WEs}3j+Slbz%Pkk2D)}cxmr2+xyGlhpO>V!R=-) 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

    vp1|ZHASVx5gSBuu3CW|P-{Da> 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�iHZPy#$|fCD)L-2^@gdh&Ac4#RH) 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%0D=!FN@Uz#<9d0j8M=b)+Jav7BbGr(yNm-};T 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 SVg-in(>K{ajiV Date: Sun, 16 Aug 2026 06:16:51 +0800 Subject: [PATCH 29/38] test(rollup): clarify stored blob semantics --- contracts/contracts/test/Rollup.t.sol | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index a6ba32d15..87741b2a6 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -908,7 +908,7 @@ contract RollupTest is L1MessageBaseTest { rollup.commitBatch(batchDataInput); hevm.stopPrank(); - // commit batch with one chunk, no tx, correctly (commitBatch requires blob when no stored hash; use commitBatchWithProof) + // Commit one batch through the permissionless proof path. V0/V1 commitBatch does not require a blob. _setupDelayAndWarpForProof(); _mockVerifierForProof(); bytes32 dataHash1 = _computeDataHash(1, 0); @@ -963,7 +963,7 @@ contract RollupTest is L1MessageBaseTest { rollup.importGenesisBatch(batchHeader0); bytes32 batchHash0 = rollup.committedBatches(0); - // commit one batch (use commitBatchWithProof: commitBatch requires no stored hash and blob tx) + // Commit one batch through the permissionless proof path. Only V2 requires at least one blob. _setupDelayAndWarpForProof(); _mockMessageQueueNotDelayedForProof(); _mockVerifierForProof(); @@ -1306,16 +1306,13 @@ contract RollupCommitStateTest is L1MessageBaseTest { assertEq(uint256(rollup.lastCommittedBatchIndex()), 1); } - /// @dev commitState must be rejected when tx carries blob (blobhash(0) != 0). - /// Contract: require(blobhash(0) == bytes32(0), "commitState must not carry blob"). - /// In test env we cannot send a blob tx (blobhash(0) is always 0), so we only assert that without blob commitState succeeds. - /// Full revert test requires a blob transaction. - function test_commitState_reverts_when_carrying_blob() public { + /// @dev A no-blob commitState succeeds by reusing the stored blob hash. + /// A blob-carrying transaction is rejected by the contract, but this test environment cannot set blobhash(0). + function test_commitState_succeeds_without_blob() public { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(alice); rollup.commitState(batchDataInput); - // Without blob in tx, commitState succeeds. Revert "commitState must not carry blob" is hit only when blobhash(0) != 0 (blob tx). assertEq(rollup.lastCommittedBatchIndex(), 1); } @@ -1331,8 +1328,8 @@ contract RollupCommitStateTest is L1MessageBaseTest { rollup.commitState(batchDataInput); } - /// @dev commitState can only be called by an active staker. - function test_commitState_only_active_staker() public { + /// @dev commitState can only be called by an active submitter. + function test_commitState_only_active_submitter() public { _setupCommitStatePrecondition(); batchDataInput = IRollup.BatchDataInput(0, _genesisBatchHeader(), 1, 0, stateRoot, stateRoot, bytes32(uint256(4))); hevm.prank(address(1)); From 7b55ff71f77489ce333b37da315457096f26c8dc Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 06:23:57 +0800 Subject: [PATCH 30/38] docs(prover): record verifier cutover inputs --- prover/README.md | 5 ++--- prover/bin/shadow-prove/contracts/README.md | 6 ++++++ prover/contracts/README.md | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/prover/README.md b/prover/README.md index 8c463ea25..d29b0950b 100644 --- a/prover/README.md +++ b/prover/README.md @@ -58,8 +58,7 @@ cargo run --release --features local --package morph-prove --bin prove -- --blo cargo run --release --package morph-prove --bin prove -- --start-block 0x35 --end-block 0x37 --rpc http://127.0.0.1:8545 --use-rpc-db --prove ``` -This command also generates a fixture that can be used to test the verification of SP1 zkVM proofs -inside Solidity. +Set `SAVE_FIXTURE=true` when a Solidity proof fixture is required. Set `PROVER_PROOF_DIR` to the consumer root; for example, `PROVER_PROOF_DIR="$PWD/bin/shadow-prove"` writes the shadow verifier fixture to `bin/shadow-prove/contracts/src/fixtures/plonk-fixture.json`. ### Retrieve the Verification Key @@ -70,4 +69,4 @@ cargo run --release --bin vkey ``` The programVKey generated above must be identical to the configuration in the L1 Verifier contract `morph-repo/contracts/src/deploy-config`. -This key serves as a cryptographic commitment to the L2 State Transition Function (STF) logic, ensuring that the off-chain computation has not been tampered with. \ No newline at end of file +This key serves as a cryptographic commitment to the L2 State Transition Function (STF) logic, ensuring that the off-chain computation has not been tampered with. diff --git a/prover/bin/shadow-prove/contracts/README.md b/prover/bin/shadow-prove/contracts/README.md index 5a9d02518..a2e793391 100644 --- a/prover/bin/shadow-prove/contracts/README.md +++ b/prover/bin/shadow-prove/contracts/README.md @@ -19,6 +19,12 @@ EvmVerifier: forge create --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 src/libs/EvmVerifier.sol:EvmVerifier --constructor-args 0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88 ``` +For an existing `ShadowRollup`, its owner must switch to the newly deployed verifier before the first proof produced by this program: + +```sh +cast send --rpc-url "$L1_RPC" --private-key "$OWNER_PRIVATE_KEY" "$SHADOW_ROLLUP" "updateVerifier(address)" "$NEW_EVM_VERIFIER" +``` + ShadowRollup ``` forge create --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 src/ShadowRollup.sol:ShadowRollup --constructor-args 53077 0x5FbDB2315678afecb367f032d93F642f64180aa3 diff --git a/prover/contracts/README.md b/prover/contracts/README.md index 1e97783f6..40ae7a590 100644 --- a/prover/contracts/README.md +++ b/prover/contracts/README.md @@ -17,5 +17,5 @@ $ forge test ### Deploy ``` -forge create --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 prover/contracts/src/EvmVerifier.sol:EvmVerifier --constructor-args 0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c -``` \ No newline at end of file +forge create --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 prover/contracts/src/EvmVerifier.sol:EvmVerifier --constructor-args 0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88 +``` From d77b1526ae92a57c0f60b38360901fcfe41d39bc Mon Sep 17 00:00:00 2001 From: Segue Date: Sun, 16 Aug 2026 07:29:35 +0800 Subject: [PATCH 31/38] fix(submitter): release stake at exit snapshot --- bindings/bin/submitter_deployed.hex | 2 +- .../bindings/centralization_cleanup_test.go | 39 +++++++++++- bindings/bindings/submitter.go | 35 ++++++++++- bindings/bindings/submitter_more.go | 4 +- contracts/contracts/l1/rollup/ISubmitter.sol | 2 +- contracts/contracts/l1/rollup/Submitter.sol | 30 +++++----- contracts/contracts/test/Submitter.t.sol | 60 +++++++++++++++---- 7 files changed, 139 insertions(+), 33 deletions(-) diff --git a/bindings/bin/submitter_deployed.hex b/bindings/bin/submitter_deployed.hex index 6ca10a562..ab7bd5a86 100644 --- a/bindings/bin/submitter_deployed.hex +++ b/bindings/bin/submitter_deployed.hex @@ -1 +1 @@ -0x608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611bc0565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611be0565b6105d2565b3480156101ef575f80fd5b5061019b6101fe366004611be0565b610678565b61019b61071e565b348015610216575f80fd5b50610239610225366004611bc0565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b6108b3565b348015610268575f80fd5b506101b2610277366004611bc0565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b6109f0565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611bc0565b610a01565b348015610326575f80fd5b5061019b610335366004611bc0565b610a92565b348015610345575f80fd5b5061019b610354366004611be0565b610c83565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611bc0565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611bc0565b610d36565b3480156103f2575f80fd5b506101b2610401366004611bc0565b610ece565b348015610411575f80fd5b5061019b610420366004611bc0565b611085565b348015610430575f80fd5b5061019b61043f366004611bf7565b6111b1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611bc0565b6115f9565b610480611693565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b61057a5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105da611693565b5f811180156105eb57506098548114155b6106375760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610680611693565b5f8111801561069157506099548114155b6106dd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107266116fa565b335f818152609c602052604090205460ff168015610769575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107b55760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546107e5903490611c6d565b90505f341180156107f857506098548110155b6108445760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108b16001606555565b565b335f818152609c602052604090205460ff1680156108f6575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610925575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109715760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b6109f8611693565b6108b15f61175a565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a5a575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a8c575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a9a6116fa565b3373ffffffffffffffffffffffffffffffffffffffff8216610afe5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b725760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e6700000000000000000000000000000000006044820152606401610571565b610b7a6117d0565b610bc65760405162461bcd60e51b815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e656400000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e909252909120805460ff19169055610c0d83826118d8565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610c6c91815260200190565b60405180910390a35050610c806001606555565b50565b610c8b611693565b5f81118015610c9b575060648111155b8015610ca95750609a548114155b610cf55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610d3e611693565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610d97575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610de35760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610e8a5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e602052604090819020805460ff19166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e4490610e819084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f4d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610571565b610f556116fa565b73ffffffffffffffffffffffffffffffffffffffff8216610f7757505f611076565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216909155609a54606490610fd59083611c80565b610fdf9190611c97565b9150610feb8282611ccf565b609b5f828254610ffb9190611c6d565b90915550506097546110239073ffffffffffffffffffffffffffffffffffffffff16836118d8565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110806001606555565b919050565b61108d611693565b6110956116fa565b73ffffffffffffffffffffffffffffffffffffffff81166110f85760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b609b54806111485760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610571565b5f609b5561115682826118d8565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161119e91815260200190565b60405180910390a250610c806001606555565b5f54610100900460ff16158080156111cf57505f54600160ff909116105b806111e85750303b1580156111e857505f5460ff166001145b61125a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610571565b5f805460ff191660011790558015611298575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166112fb5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff85161580159061133657505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113825760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610571565b5f84116113d15760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b5f83116114205760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b5f82118015611430575060648211155b61147c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b611484611994565b61148c611a18565b6114958661175a565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156115f1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611601611693565b73ffffffffffffffffffffffffffffffffffffffff811661168a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610571565b610c808161175a565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108b15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610571565b60026065540361174c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610571565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611840573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118649190611ce2565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118d19190611ce2565b1491505090565b805f036118e3575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611939576040519150601f19603f3d011682016040523d82523d5f602084013e61193e565b606091505b505090508061198f5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610571565b505050565b5f54610100900460ff16611a105760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611a9c565b5f54610100900460ff16611a945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611b21565b5f54610100900460ff16611b185760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b13361175a565b5f54610100900460ff166117535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b803573ffffffffffffffffffffffffffffffffffffffff81168114611080575f80fd5b5f60208284031215611bd0575f80fd5b611bd982611b9d565b9392505050565b5f60208284031215611bf0575f80fd5b5035919050565b5f805f805f60a08688031215611c0b575f80fd5b611c1486611b9d565b9450611c2260208701611b9d565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8c57610a8c611c40565b8082028115828204841417610a8c57610a8c611c40565b5f82611cca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8c57610a8c611c40565b5f60208284031215611cf2575f80fd5b505191905056fea164736f6c6343000818000a +0x608060405260043610610183575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b41461045b578063ec5ffac21461047a578063f2fde38b1461048f575f80fd5b8063c36f41e2146103fe578063c96be4cb1461041d578063cde4cd111461043c575f80fd5b8063ab8c53dc116100ac578063ab8c53dc1461038f578063b2dd5c07146103a4578063bfa02ba9146103d2575f80fd5b80639f8a13d714610332578063a3066aab14610351578063a4f209b014610370575f80fd5b80633bf1944b1161013157806352d472eb1161010c57806352d472eb146102be578063715018a6146102d35780638da5cb5b146102e7575f80fd5b80633bf1944b146102545780633ccfd60b1461027f5780634262336014610293575f80fd5b8063359289911161016157806335928991146101ef5780633a4b66f11461020e5780633baf3a2f14610216575f80fd5b8063072900f9146101875780630d13fd7b146101a8578063233e9903146101d0575b5f80fd5b348015610192575f80fd5b506101a66101a1366004611c12565b6104ae565b005b3480156101b3575f80fd5b506101bd60995481565b6040519081526020015b60405180910390f35b3480156101db575f80fd5b506101a66101ea366004611c32565b610608565b3480156101fa575f80fd5b506101a6610209366004611c32565b6106ae565b6101a6610754565b348015610221575f80fd5b50610244610230366004611c12565b609e6020525f908152604090205460ff1681565b60405190151581526020016101c7565b34801561025f575f80fd5b506101bd61026e366004611c12565b609f6020525f908152604090205481565b34801561028a575f80fd5b506101a66108e9565b34801561029e575f80fd5b506101bd6102ad366004611c12565b609d6020525f908152604090205481565b3480156102c9575f80fd5b506101bd609a5481565b3480156102de575f80fd5b506101a66109ec565b3480156102f2575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c7565b34801561033d575f80fd5b5061024461034c366004611c12565b6109fd565b34801561035c575f80fd5b506101a661036b366004611c12565b610a8e565b34801561037b575f80fd5b506101a661038a366004611c32565b610d21565b34801561039a575f80fd5b506101bd609b5481565b3480156103af575f80fd5b506102446103be366004611c12565b609c6020525f908152604090205460ff1681565b3480156103dd575f80fd5b5060975461030d9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610409575f80fd5b506101a6610418366004611c12565b610dd4565b348015610428575f80fd5b506101bd610437366004611c12565b610f0c565b348015610447575f80fd5b506101a6610456366004611c12565b6110ce565b348015610466575f80fd5b506101a6610475366004611c49565b6111fa565b348015610485575f80fd5b506101bd60985481565b34801561049a575f80fd5b506101a66104a9366004611c12565b611642565b6104b66116dc565b73ffffffffffffffffffffffffffffffffffffffff811615801590610500575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b8015610531575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b801561055f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b6105b05760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6106106116dc565b5f8111801561062157506098548114155b61066d5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105a7565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b6106b66116dc565b5f811180156106c757506099548114155b6107135760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105a7565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b61075c611743565b335f818152609c602052604090205460ff16801561079f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107eb5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c650000000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604081205461081b903490611cbf565b90505f3411801561082e57506098548110155b61087a5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b650000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108e76001606555565b565b335f818152609c602052604090205460ff16801561092c575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b801561095b575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109a75760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c650000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020546109e99082906117a3565b50565b6109f46116dc565b6108e75f6118b4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a56575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a88575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a96611743565b3373ffffffffffffffffffffffffffffffffffffffff8216610afa5760405162461bcd60e51b815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b6e5760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e67000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff8082165f908152609f60209081526040918290205460975483517f059def6100000000000000000000000000000000000000000000000000000000815293519194169263059def619260048083019391928290030181865afa158015610beb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0f9190611cd2565b1015610c5d5760405162461bcd60e51b815260206004820152601e60248201527f7769746864726177616c206261746368206e6f742066696e616c697a6564000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e8352818420805460ff19169055609f909252822091909155610cae838261192a565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610d0d91815260200190565b60405180910390a350506109e96001606555565b610d296116dc565b5f81118015610d39575060648111155b8015610d475750609a548114155b610d935760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105a7565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610ddc6116dc565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610e35575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610e815760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610ec857610ec882826117a3565b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f8b5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016105a7565b610f93611743565b73ffffffffffffffffffffffffffffffffffffffff8216610fb557505f6110bf565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e84528285208054909216909155609f909252822091909155609a5460649061101e9083611ce9565b6110289190611d00565b91506110348282611d38565b609b5f8282546110449190611cbf565b909155505060975461106c9073ffffffffffffffffffffffffffffffffffffffff168361192a565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110c96001606555565b919050565b6110d66116dc565b6110de611743565b73ffffffffffffffffffffffffffffffffffffffff81166111415760405162461bcd60e51b815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105a7565b609b54806111915760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e67000000000000000000000000000060448201526064016105a7565b5f609b5561119f828261192a565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9826040516111e791815260200190565b60405180910390a2506109e96001606555565b5f54610100900460ff161580801561121857505f54600160ff909116105b806112315750303b15801561123157505f5460ff166001145b6112a35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016105a7565b5f805460ff1916600117905580156112e1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166113445760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff85161580159061137f57505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113cb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016105a7565b5f841161141a5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105a7565b5f83116114695760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105a7565b5f82118015611479575060648211155b6114c55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105a7565b6114cd6119e6565b6114d5611a6a565b6114de866118b4565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1801561163a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61164a6116dc565b73ffffffffffffffffffffffffffffffffffffffff81166116d35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016105a7565b6109e9816118b4565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108e75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105a7565b6002606554036117955760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105a7565b6002606555565b6001606555565b73ffffffffffffffffffffffffffffffffffffffff8083165f908152609e6020908152604091829020805460ff1916600117905560975482517f121dcd50000000000000000000000000000000000000000000000000000000008152925193169263121dcd509260048082019392918290030181865afa158015611829573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184d9190611cd2565b73ffffffffffffffffffffffffffffffffffffffff83165f818152609f6020526040908190209290925590517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44906118a89084815260200190565b60405180910390a25050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b805f03611935575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461198b576040519150601f19603f3d011682016040523d82523d5f602084013e611990565b606091505b50509050806119e15760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016105a7565b505050565b5f54610100900460ff16611a625760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7611aee565b5f54610100900460ff16611ae65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7611b73565b5f54610100900460ff16611b6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7336118b4565b5f54610100900460ff1661179c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c9575f80fd5b5f60208284031215611c22575f80fd5b611c2b82611bef565b9392505050565b5f60208284031215611c42575f80fd5b5035919050565b5f805f805f60a08688031215611c5d575f80fd5b611c6686611bef565b9450611c7460208701611bef565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8857610a88611c92565b5f60208284031215611ce2575f80fd5b5051919050565b8082028115828204841417610a8857610a88611c92565b5f82611d33577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8857610a88611c9256fea164736f6c6343000818000a diff --git a/bindings/bindings/centralization_cleanup_test.go b/bindings/bindings/centralization_cleanup_test.go index 4947b69bb..3f9aa3dd7 100644 --- a/bindings/bindings/centralization_cleanup_test.go +++ b/bindings/bindings/centralization_cleanup_test.go @@ -65,11 +65,23 @@ func TestCurrentSubmitterBindingShape(t *testing.T) { "slash", "stake", "withdraw", + "withdrawalBatchIndex", } { if _, ok := current.Methods[name]; !ok { t.Fatalf("generated Submitter ABI is missing %s", name) } } + + method := current.Methods["withdrawalBatchIndex"] + if got := hex.EncodeToString(method.ID); got != "3bf1944b" { + t.Fatalf("withdrawalBatchIndex selector = %s, want 3bf1944b", got) + } + if len(method.Inputs) != 1 || method.Inputs[0].Type.String() != "address" { + t.Fatalf("withdrawalBatchIndex input must be address: %v", method.Inputs) + } + if len(method.Outputs) != 1 || method.Outputs[0].Type.String() != "uint256" { + t.Fatalf("withdrawalBatchIndex output must be uint256: %v", method.Outputs) + } } func TestCurrentStorageLayoutsAreGenerated(t *testing.T) { @@ -93,7 +105,30 @@ func TestCurrentStorageLayoutsAreGenerated(t *testing.T) { t.Fatalf("Rollup storage layout is missing entries: %v", wantRollupSlots) } - if len(SubmitterStorageLayout.Storage) == 0 { - t.Fatal("Submitter storage layout was not generated") + wantSubmitterSlots := map[string]uint{ + "withdrawing": 158, + "withdrawalBatchIndex": 159, + } + foundFinalGap := false + for _, entry := range SubmitterStorageLayout.Storage { + if want, ok := wantSubmitterSlots[entry.Label]; ok { + if entry.Slot != want { + t.Fatalf("Submitter %s slot = %d, want %d", entry.Label, entry.Slot, want) + } + delete(wantSubmitterSlots, entry.Label) + } + if entry.Label == "__gap" && entry.Slot == 160 { + layoutType := SubmitterStorageLayout.Types[entry.Type] + if layoutType.Label != "uint256[49]" { + t.Fatalf("Submitter final gap type = %s, want uint256[49]", layoutType.Label) + } + foundFinalGap = true + } + } + if len(wantSubmitterSlots) != 0 { + t.Fatalf("Submitter storage layout is missing entries: %v", wantSubmitterSlots) + } + if !foundFinalGap { + t.Fatal("Submitter storage layout is missing the final gap at slot 160") } } diff --git a/bindings/bindings/submitter.go b/bindings/bindings/submitter.go index c929a6c9e..e435fce19 100644 --- a/bindings/bindings/submitter.go +++ b/bindings/bindings/submitter.go @@ -31,8 +31,8 @@ var ( // SubmitterMetaData contains all meta data concerning the Submitter contract. var SubmitterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"MinimumStakeUpdated\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"addSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rollupContract_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardPercentage_\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"isActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"registered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"removeSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setMinimumStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"stakeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"withdrawing\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isWithdrawing\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561000f575f80fd5b5061001861001d565b6100d9565b5f54610100900460ff16156100885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100d7575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611d06806100e65f395ff3fe608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611bc0565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611be0565b6105d2565b3480156101ef575f80fd5b5061019b6101fe366004611be0565b610678565b61019b61071e565b348015610216575f80fd5b50610239610225366004611bc0565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b6108b3565b348015610268575f80fd5b506101b2610277366004611bc0565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b6109f0565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611bc0565b610a01565b348015610326575f80fd5b5061019b610335366004611bc0565b610a92565b348015610345575f80fd5b5061019b610354366004611be0565b610c83565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611bc0565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611bc0565b610d36565b3480156103f2575f80fd5b506101b2610401366004611bc0565b610ece565b348015610411575f80fd5b5061019b610420366004611bc0565b611085565b348015610430575f80fd5b5061019b61043f366004611bf7565b6111b1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611bc0565b6115f9565b610480611693565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b61057a5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6105da611693565b5f811180156105eb57506098548114155b6106375760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b610680611693565b5f8111801561069157506099548114155b6106dd5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107266116fa565b335f818152609c602052604090205460ff168015610769575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107b55760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c65000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546107e5903490611c6d565b90505f341180156107f857506098548110155b6108445760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b65000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108b16001606555565b565b335f818152609c602052604090205460ff1680156108f6575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610925575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109715760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c65000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c60209081526040808320805460ff19908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b6109f8611693565b6108b15f61175a565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a5a575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a8c575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a9a6116fa565b3373ffffffffffffffffffffffffffffffffffffffff8216610afe5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b725760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e6700000000000000000000000000000000006044820152606401610571565b610b7a6117d0565b610bc65760405162461bcd60e51b815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e656400000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e909252909120805460ff19169055610c0d83826118d8565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610c6c91815260200190565b60405180910390a35050610c806001606555565b50565b610c8b611693565b5f81118015610c9b575060648111155b8015610ca95750609a548114155b610cf55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610d3e611693565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610d97575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610de35760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610e8a5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e602052604090819020805460ff19166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e4490610e819084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f4d5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e74726163740000000000000000000000006044820152606401610571565b610f556116fa565b73ffffffffffffffffffffffffffffffffffffffff8216610f7757505f611076565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e90935292208054909216909155609a54606490610fd59083611c80565b610fdf9190611c97565b9150610feb8282611ccf565b609b5f828254610ffb9190611c6d565b90915550506097546110239073ffffffffffffffffffffffffffffffffffffffff16836118d8565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110806001606555565b919050565b61108d611693565b6110956116fa565b73ffffffffffffffffffffffffffffffffffffffff81166110f85760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964207265636569766572000000000000000000000000000000006044820152606401610571565b609b54806111485760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e6700000000000000000000000000006044820152606401610571565b5f609b5561115682826118d8565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd98260405161119e91815260200190565b60405180910390a250610c806001606555565b5f54610100900460ff16158080156111cf57505f54600160ff909116105b806111e85750303b1580156111e857505f5460ff166001145b61125a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610571565b5f805460ff191660011790558015611298575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166112fb5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e6572000000000000000000000000000000000000006044820152606401610571565b73ffffffffffffffffffffffffffffffffffffffff85161580159061133657505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113825760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e74726163740000000000000000006044820152606401610571565b5f84116113d15760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b6500000000000000000000006044820152606401610571565b5f83116114205760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f736974000000000000006044820152606401610571565b5f82118015611430575060648211155b61147c5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e74616765000000000000006044820152606401610571565b611484611994565b61148c611a18565b6114958661175a565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156115f1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611601611693565b73ffffffffffffffffffffffffffffffffffffffff811661168a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610571565b610c808161175a565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108b15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610571565b60026065540361174c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610571565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611840573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118649190611ce2565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118d19190611ce2565b1491505090565b805f036118e3575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611939576040519150601f19603f3d011682016040523d82523d5f602084013e61193e565b606091505b505090508061198f5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610571565b505050565b5f54610100900460ff16611a105760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611a9c565b5f54610100900460ff16611a945760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b1611b21565b5f54610100900460ff16611b185760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b6108b13361175a565b5f54610100900460ff166117535760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610571565b803573ffffffffffffffffffffffffffffffffffffffff81168114611080575f80fd5b5f60208284031215611bd0575f80fd5b611bd982611b9d565b9392505050565b5f60208284031215611bf0575f80fd5b5035919050565b5f805f805f60a08688031215611c0b575f80fd5b611c1486611b9d565b9450611c2260208701611b9d565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8c57610a8c611c40565b8082028115828204841417610a8c57610a8c611c40565b5f82611cca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8c57610a8c611c40565b5f60208284031215611cf2575f80fd5b505191905056fea164736f6c6343000818000a", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"ChallengeDepositUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"MinimumStakeUpdated\",\"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\":false,\"internalType\":\"uint256\",\"name\":\"oldValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newValue\",\"type\":\"uint256\"}],\"name\":\"RewardPercentageUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SlashRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"name\":\"Slashed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"SubmitterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"addSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimSlashRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rollupContract_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardPercentage_\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"isActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"registered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isRegistered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"removeSubmitter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rewardPercentage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setMinimumStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"slash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slashRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"stakeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateChallengeDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"withdrawalBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"name\":\"withdrawing\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isWithdrawing\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561000f575f80fd5b5061001861001d565b6100d9565b5f54610100900460ff16156100885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146100d7575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611d58806100e65f395ff3fe608060405260043610610183575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b41461045b578063ec5ffac21461047a578063f2fde38b1461048f575f80fd5b8063c36f41e2146103fe578063c96be4cb1461041d578063cde4cd111461043c575f80fd5b8063ab8c53dc116100ac578063ab8c53dc1461038f578063b2dd5c07146103a4578063bfa02ba9146103d2575f80fd5b80639f8a13d714610332578063a3066aab14610351578063a4f209b014610370575f80fd5b80633bf1944b1161013157806352d472eb1161010c57806352d472eb146102be578063715018a6146102d35780638da5cb5b146102e7575f80fd5b80633bf1944b146102545780633ccfd60b1461027f5780634262336014610293575f80fd5b8063359289911161016157806335928991146101ef5780633a4b66f11461020e5780633baf3a2f14610216575f80fd5b8063072900f9146101875780630d13fd7b146101a8578063233e9903146101d0575b5f80fd5b348015610192575f80fd5b506101a66101a1366004611c12565b6104ae565b005b3480156101b3575f80fd5b506101bd60995481565b6040519081526020015b60405180910390f35b3480156101db575f80fd5b506101a66101ea366004611c32565b610608565b3480156101fa575f80fd5b506101a6610209366004611c32565b6106ae565b6101a6610754565b348015610221575f80fd5b50610244610230366004611c12565b609e6020525f908152604090205460ff1681565b60405190151581526020016101c7565b34801561025f575f80fd5b506101bd61026e366004611c12565b609f6020525f908152604090205481565b34801561028a575f80fd5b506101a66108e9565b34801561029e575f80fd5b506101bd6102ad366004611c12565b609d6020525f908152604090205481565b3480156102c9575f80fd5b506101bd609a5481565b3480156102de575f80fd5b506101a66109ec565b3480156102f2575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c7565b34801561033d575f80fd5b5061024461034c366004611c12565b6109fd565b34801561035c575f80fd5b506101a661036b366004611c12565b610a8e565b34801561037b575f80fd5b506101a661038a366004611c32565b610d21565b34801561039a575f80fd5b506101bd609b5481565b3480156103af575f80fd5b506102446103be366004611c12565b609c6020525f908152604090205460ff1681565b3480156103dd575f80fd5b5060975461030d9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610409575f80fd5b506101a6610418366004611c12565b610dd4565b348015610428575f80fd5b506101bd610437366004611c12565b610f0c565b348015610447575f80fd5b506101a6610456366004611c12565b6110ce565b348015610466575f80fd5b506101a6610475366004611c49565b6111fa565b348015610485575f80fd5b506101bd60985481565b34801561049a575f80fd5b506101a66104a9366004611c12565b611642565b6104b66116dc565b73ffffffffffffffffffffffffffffffffffffffff811615801590610500575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b8015610531575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b801561055f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b6105b05760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020526040808220805460ff19166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6106106116dc565b5f8111801561062157506098548114155b61066d5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105a7565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b6106b66116dc565b5f811180156106c757506099548114155b6107135760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105a7565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b61075c611743565b335f818152609c602052604090205460ff16801561079f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b6107eb5760405162461bcd60e51b815260206004820152600d60248201527f6e6f74207374616b6561626c650000000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604081205461081b903490611cbf565b90505f3411801561082e57506098548110155b61087a5760405162461bcd60e51b815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b650000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506108e76001606555565b565b335f818152609c602052604090205460ff16801561092c575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b801561095b575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b6109a75760405162461bcd60e51b815260206004820152601060248201527f6e6f7420776974686472617761626c650000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020546109e99082906117a3565b50565b6109f46116dc565b6108e75f6118b4565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610a56575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610a88575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610a96611743565b3373ffffffffffffffffffffffffffffffffffffffff8216610afa5760405162461bcd60e51b815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610b6e5760405162461bcd60e51b815260206004820152600f60248201527f6e6f74207769746864726177696e67000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff8082165f908152609f60209081526040918290205460975483517f059def6100000000000000000000000000000000000000000000000000000000815293519194169263059def619260048083019391928290030181865afa158015610beb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0f9190611cd2565b1015610c5d5760405162461bcd60e51b815260206004820152601e60248201527f7769746864726177616c206261746368206e6f742066696e616c697a6564000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e8352818420805460ff19169055609f909252822091909155610cae838261192a565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610d0d91815260200190565b60405180910390a350506109e96001606555565b610d296116dc565b5f81118015610d39575060648111155b8015610d475750609a548114155b610d935760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105a7565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610ddc6116dc565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610e35575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610e815760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c60209081526040808320805460ff19169055609d9091529020548015610ec857610ec882826117a3565b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f8b5760405162461bcd60e51b815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016105a7565b610f93611743565b73ffffffffffffffffffffffffffffffffffffffff8216610fb557505f6110bf565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c8452828520805460ff1990811690915591859055609e84528285208054909216909155609f909252822091909155609a5460649061101e9083611ce9565b6110289190611d00565b91506110348282611d38565b609b5f8282546110449190611cbf565b909155505060975461106c9073ffffffffffffffffffffffffffffffffffffffff168361192a565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6110c96001606555565b919050565b6110d66116dc565b6110de611743565b73ffffffffffffffffffffffffffffffffffffffff81166111415760405162461bcd60e51b815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105a7565b609b54806111915760405162461bcd60e51b815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e67000000000000000000000000000060448201526064016105a7565b5f609b5561119f828261192a565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9826040516111e791815260200190565b60405180910390a2506109e96001606555565b5f54610100900460ff161580801561121857505f54600160ff909116105b806112315750303b15801561123157505f5460ff166001145b6112a35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016105a7565b5f805460ff1916600117905580156112e1575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff86166113445760405162461bcd60e51b815260206004820152600d60248201527f696e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016105a7565b73ffffffffffffffffffffffffffffffffffffffff85161580159061137f57505f8573ffffffffffffffffffffffffffffffffffffffff163b115b6113cb5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016105a7565b5f841161141a5760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105a7565b5f83116114695760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105a7565b5f82118015611479575060648211155b6114c55760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105a7565b6114cd6119e6565b6114d5611a6a565b6114de866118b4565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1801561163a575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61164a6116dc565b73ffffffffffffffffffffffffffffffffffffffff81166116d35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016105a7565b6109e9816118b4565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108e75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105a7565b6002606554036117955760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105a7565b6002606555565b6001606555565b73ffffffffffffffffffffffffffffffffffffffff8083165f908152609e6020908152604091829020805460ff1916600117905560975482517f121dcd50000000000000000000000000000000000000000000000000000000008152925193169263121dcd509260048082019392918290030181865afa158015611829573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184d9190611cd2565b73ffffffffffffffffffffffffffffffffffffffff83165f818152609f6020526040908190209290925590517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44906118a89084815260200190565b60405180910390a25050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b805f03611935575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f811461198b576040519150601f19603f3d011682016040523d82523d5f602084013e611990565b606091505b50509050806119e15760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016105a7565b505050565b5f54610100900460ff16611a625760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7611aee565b5f54610100900460ff16611ae65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7611b73565b5f54610100900460ff16611b6a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b6108e7336118b4565b5f54610100900460ff1661179c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105a7565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c9575f80fd5b5f60208284031215611c22575f80fd5b611c2b82611bef565b9392505050565b5f60208284031215611c42575f80fd5b5035919050565b5f805f805f60a08688031215611c5d575f80fd5b611c6686611bef565b9450611c7460208701611bef565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8857610a88611c92565b5f60208284031215611ce2575f80fd5b5051919050565b8082028115828204841417610a8857610a88611c92565b5f82611d33577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8857610a88611c9256fea164736f6c6343000818000a", } // SubmitterABI is the input ABI used to generate the binding from. @@ -481,6 +481,37 @@ func (_Submitter *SubmitterCallerSession) StakeOf(submitter common.Address) (*bi return _Submitter.Contract.StakeOf(&_Submitter.CallOpts, submitter) } +// WithdrawalBatchIndex is a free data retrieval call binding the contract method 0x3bf1944b. +// +// Solidity: function withdrawalBatchIndex(address submitter) view returns(uint256 batchIndex) +func (_Submitter *SubmitterCaller) WithdrawalBatchIndex(opts *bind.CallOpts, submitter common.Address) (*big.Int, error) { + var out []interface{} + err := _Submitter.contract.Call(opts, &out, "withdrawalBatchIndex", submitter) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// WithdrawalBatchIndex is a free data retrieval call binding the contract method 0x3bf1944b. +// +// Solidity: function withdrawalBatchIndex(address submitter) view returns(uint256 batchIndex) +func (_Submitter *SubmitterSession) WithdrawalBatchIndex(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.WithdrawalBatchIndex(&_Submitter.CallOpts, submitter) +} + +// WithdrawalBatchIndex is a free data retrieval call binding the contract method 0x3bf1944b. +// +// Solidity: function withdrawalBatchIndex(address submitter) view returns(uint256 batchIndex) +func (_Submitter *SubmitterCallerSession) WithdrawalBatchIndex(submitter common.Address) (*big.Int, error) { + return _Submitter.Contract.WithdrawalBatchIndex(&_Submitter.CallOpts, submitter) +} + // Withdrawing is a free data retrieval call binding the contract method 0x3baf3a2f. // // Solidity: function withdrawing(address submitter) view returns(bool isWithdrawing) diff --git a/bindings/bindings/submitter_more.go b/bindings/bindings/submitter_more.go index e2538faf0..52d08b1bc 100644 --- a/bindings/bindings/submitter_more.go +++ b/bindings/bindings/submitter_more.go @@ -9,11 +9,11 @@ import ( "morph-l2/bindings/solc" ) -const SubmitterStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1016_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1016_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"minimumStake\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"registered\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"stakeOf\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"withdrawing\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_array(t_uint256)1017_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1016_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1017_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" +const SubmitterStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1018_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"_status\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_uint256\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1017_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rollupContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"minimumStake\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"challengeDeposit\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"rewardPercentage\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"slashRemaining\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_uint256\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"registered\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"stakeOf\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"withdrawing\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"withdrawalBatchIndex\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Submitter.sol:Submitter\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_array(t_uint256)1017_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1017_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1018_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" var SubmitterStorageLayout = new(solc.StorageLayout) -var SubmitterDeployedBin = "0x608060405260043610610178575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b414610425578063ec5ffac214610444578063f2fde38b14610459575f80fd5b8063c36f41e2146103c8578063c96be4cb146103e7578063cde4cd1114610406575f80fd5b8063ab8c53dc116100ac578063ab8c53dc14610359578063b2dd5c071461036e578063bfa02ba91461039c575f80fd5b80639f8a13d7146102fc578063a3066aab1461031b578063a4f209b01461033a575f80fd5b80633baf3a2f1161013157806352d472eb1161010c57806352d472eb14610288578063715018a61461029d5780638da5cb5b146102b1575f80fd5b80633baf3a2f1461020b5780633ccfd60b14610249578063426233601461025d575f80fd5b8063233e990311610161578063233e9903146101c557806335928991146101e45780633a4b66f114610203575f80fd5b8063072900f91461017c5780630d13fd7b1461019d575b5f80fd5b348015610187575f80fd5b5061019b610196366004611f6a565b610478565b005b3480156101a8575f80fd5b506101b260995481565b6040519081526020015b60405180910390f35b3480156101d0575f80fd5b5061019b6101df366004611f8a565b61060a565b3480156101ef575f80fd5b5061019b6101fe366004611f8a565b6106ca565b61019b61078a565b348015610216575f80fd5b50610239610225366004611f6a565b609e6020525f908152604090205460ff1681565b60405190151581526020016101bc565b348015610254575f80fd5b5061019b610953565b348015610268575f80fd5b506101b2610277366004611f6a565b609d6020525f908152604090205481565b348015610293575f80fd5b506101b2609a5481565b3480156102a8575f80fd5b5061019b610ac8565b3480156102bc575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b348015610307575f80fd5b50610239610316366004611f6a565b610ad9565b348015610326575f80fd5b5061019b610335366004611f6a565b610b6a565b348015610345575f80fd5b5061019b610354366004611f8a565b610dc7565b348015610364575f80fd5b506101b2609b5481565b348015610379575f80fd5b50610239610388366004611f6a565b609c6020525f908152604090205460ff1681565b3480156103a7575f80fd5b506097546102d79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d3575f80fd5b5061019b6103e2366004611f6a565b610e94565b3480156103f2575f80fd5b506101b2610401366004611f6a565b611082565b348015610411575f80fd5b5061019b610420366004611f6a565b611271565b348015610430575f80fd5b5061019b61043f366004611fa1565b6113d1565b34801561044f575f80fd5b506101b260985481565b348015610464575f80fd5b5061019b610473366004611f6a565b6118d3565b610480611987565b73ffffffffffffffffffffffffffffffffffffffff8116158015906104ca575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b80156104fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b8015610529575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b610594576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b610612611987565b5f8111801561062357506098548114155b610689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b650000000000000000000000604482015260640161058b565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b6106d2611987565b5f811180156106e357506099548114155b610749576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f73697400000000000000604482015260640161058b565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b610792611a08565b335f818152609c602052604090205460ff1680156107d5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b61083b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6e6f74207374616b6561626c6500000000000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604081205461086b903490612017565b90505f3411801561087e57506098548110155b6108e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b6500000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506109516001606555565b565b335f818152609c602052604090205460ff168015610996575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b80156109c5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b610a2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420776974686472617761626c6500000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116909155609e835281842080549091166001179055609d8252918290205491519182527fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44910160405180910390a250565b610ad0611987565b6109515f611a82565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610b32575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610b64575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610b72611a08565b3373ffffffffffffffffffffffffffffffffffffffff8216610bf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c696420726563656976657200000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f74207769746864726177696e670000000000000000000000000000000000604482015260640161058b565b610c86611af8565b610cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f726f6c6c7570206e6f7420647261696e65640000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610d518382611c00565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610db091815260200190565b60405180910390a35050610dc46001606555565b50565b610dcf611987565b5f81118015610ddf575060648111155b8015610ded5750609a548114155b610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e7461676500000000000000604482015260640161058b565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610e9c611987565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610ef5575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d6974746572000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609d909152902054801561103e5773ffffffffffffffffffffffffffffffffffffffff82165f818152609e60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e44906110359084815260200190565b60405180910390a25b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e7472616374000000000000000000000000604482015260640161058b565b611123611a08565b73ffffffffffffffffffffffffffffffffffffffff821661114557505f611262565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c845282852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690915591859055609e90935292208054909216909155609a546064906111c1908361202a565b6111cb9190612041565b91506111d78282612079565b609b5f8282546111e79190612017565b909155505060975461120f9073ffffffffffffffffffffffffffffffffffffffff1683611c00565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b61126c6001606555565b919050565b611279611987565b611281611a08565b73ffffffffffffffffffffffffffffffffffffffff81166112fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c696420726563656976657200000000000000000000000000000000604482015260640161058b565b609b5480611368576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e670000000000000000000000000000604482015260640161058b565b5f609b556113768282611c00565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9826040516113be91815260200190565b60405180910390a250610dc46001606555565b5f54610100900460ff16158080156113ef57505f54600160ff909116105b806114085750303b15801561140857505f5460ff166001145b611494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161058b565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156114f0575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861661156d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c6964206f776e657200000000000000000000000000000000000000604482015260640161058b565b73ffffffffffffffffffffffffffffffffffffffff8516158015906115a857505f8573ffffffffffffffffffffffffffffffffffffffff163b115b61160e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e7472616374000000000000000000604482015260640161058b565b5f8411611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b650000000000000000000000604482015260640161058b565b5f83116116e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f73697400000000000000604482015260640161058b565b5f821180156116f0575060648211155b611756576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e7461676500000000000000604482015260640161058b565b61175e611cd6565b611766611d74565b61176f86611a82565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156118cb575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6118db611987565b73ffffffffffffffffffffffffffffffffffffffff811661197e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161058b565b610dc481611a82565b60335473ffffffffffffffffffffffffffffffffffffffff163314610951576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161058b565b600260655403611a74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161058b565b6002606555565b6001606555565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b609754604080517f059def6100000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff1691829163059def61916004808201926020929091908290030181865afa158015611b68573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8c919061208c565b8173ffffffffffffffffffffffffffffffffffffffff1663121dcd506040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf9919061208c565b1491505090565b805f03611c0b575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611c61576040519150601f19603f3d011682016040523d82523d5f602084013e611c66565b606091505b5050905080611cd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161058b565b505050565b5f54610100900460ff16611d6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b610951611e12565b5f54610100900460ff16611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b610951611eb1565b5f54610100900460ff16611ea8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b61095133611a82565b5f54610100900460ff16611a7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161058b565b803573ffffffffffffffffffffffffffffffffffffffff8116811461126c575f80fd5b5f60208284031215611f7a575f80fd5b611f8382611f47565b9392505050565b5f60208284031215611f9a575f80fd5b5035919050565b5f805f805f60a08688031215611fb5575f80fd5b611fbe86611f47565b9450611fcc60208701611f47565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610b6457610b64611fea565b8082028115828204841417610b6457610b64611fea565b5f82612074577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610b6457610b64611fea565b5f6020828403121561209c575f80fd5b505191905056fea164736f6c6343000818000a" +var SubmitterDeployedBin = "0x608060405260043610610183575f3560e01c80639f8a13d7116100d1578063c36f41e21161007c578063d13f90b411610057578063d13f90b41461045b578063ec5ffac21461047a578063f2fde38b1461048f575f80fd5b8063c36f41e2146103fe578063c96be4cb1461041d578063cde4cd111461043c575f80fd5b8063ab8c53dc116100ac578063ab8c53dc1461038f578063b2dd5c07146103a4578063bfa02ba9146103d2575f80fd5b80639f8a13d714610332578063a3066aab14610351578063a4f209b014610370575f80fd5b80633bf1944b1161013157806352d472eb1161010c57806352d472eb146102be578063715018a6146102d35780638da5cb5b146102e7575f80fd5b80633bf1944b146102545780633ccfd60b1461027f5780634262336014610293575f80fd5b8063359289911161016157806335928991146101ef5780633a4b66f11461020e5780633baf3a2f14610216575f80fd5b8063072900f9146101875780630d13fd7b146101a8578063233e9903146101d0575b5f80fd5b348015610192575f80fd5b506101a66101a1366004611fbc565b6104ae565b005b3480156101b3575f80fd5b506101bd60995481565b6040519081526020015b60405180910390f35b3480156101db575f80fd5b506101a66101ea366004611fdc565b610640565b3480156101fa575f80fd5b506101a6610209366004611fdc565b610700565b6101a66107c0565b348015610221575f80fd5b50610244610230366004611fbc565b609e6020525f908152604090205460ff1681565b60405190151581526020016101c7565b34801561025f575f80fd5b506101bd61026e366004611fbc565b609f6020525f908152604090205481565b34801561028a575f80fd5b506101a6610989565b34801561029e575f80fd5b506101bd6102ad366004611fbc565b609d6020525f908152604090205481565b3480156102c9575f80fd5b506101bd609a5481565b3480156102de575f80fd5b506101a6610ac4565b3480156102f2575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c7565b34801561033d575f80fd5b5061024461034c366004611fbc565b610ad5565b34801561035c575f80fd5b506101a661036b366004611fbc565b610b66565b34801561037b575f80fd5b506101a661038a366004611fdc565b610e65565b34801561039a575f80fd5b506101bd609b5481565b3480156103af575f80fd5b506102446103be366004611fbc565b609c6020525f908152604090205460ff1681565b3480156103dd575f80fd5b5060975461030d9073ffffffffffffffffffffffffffffffffffffffff1681565b348015610409575f80fd5b506101a6610418366004611fbc565b610f32565b348015610428575f80fd5b506101bd610437366004611fbc565b6110a2565b348015610447575f80fd5b506101a6610456366004611fbc565b61129c565b348015610466575f80fd5b506101a6610475366004611ff3565b6113fc565b348015610485575f80fd5b506101bd60985481565b34801561049a575f80fd5b506101a66104a9366004611fbc565b6118fe565b6104b66119b2565b73ffffffffffffffffffffffffffffffffffffffff811615801590610500575073ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff16155b8015610531575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b801561055f575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d6020526040902054155b6105ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609c602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b9190a250565b6106486119b2565b5f8111801561065957506098548114155b6106bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c1565b60985460408051918252602082018390527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1609855565b6107086119b2565b5f8111801561071957506099548114155b61077f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c1565b60995460408051918252602082018390527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1609955565b6107c8611a33565b335f818152609c602052604090205460ff16801561080b575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6e6f74207374616b6561626c650000000000000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60205260408120546108a1903490612069565b90505f341180156108b457506098548110155b61091a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62656c6f77206d696e696d756d207374616b650000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff82165f818152609d602090815260409182902084905581513481529081018490527f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90910160405180910390a250506109876001606555565b565b335f818152609c602052604090205460ff1680156109cc575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b80156109fb575073ffffffffffffffffffffffffffffffffffffffff81165f908152609d602052604090205415155b610a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e6f7420776974686472617761626c650000000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609d909152902054610ac1908290611aad565b50565b610acc6119b2565b6109875f611bdc565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604081205460ff168015610b2e575073ffffffffffffffffffffffffffffffffffffffff82165f908152609e602052604090205460ff16155b8015610b60575060985473ffffffffffffffffffffffffffffffffffffffff83165f908152609d602052604090205410155b92915050565b610b6e611a33565b3373ffffffffffffffffffffffffffffffffffffffff8216610bec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16610c7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f74207769746864726177696e67000000000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff8082165f908152609f60209081526040918290205460975483517f059def6100000000000000000000000000000000000000000000000000000000815293519194169263059def619260048083019391928290030181865afa158015610cf7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1b919061207c565b1015610d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7769746864726177616c206261746368206e6f742066696e616c697a6564000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609d60209081526040808320805490849055609e835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609f909252822091909155610df28382611c52565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8188e2b4d95f73db30690b4103c71159349bb897df928902c6330ef99e45fef383604051610e5191815260200190565b60405180910390a35050610ac16001606555565b610e6d6119b2565b5f81118015610e7d575060648111155b8015610e8b5750609a548114155b610ef1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c1565b609a5460408051918252602082018390527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a1609a55565b610f3a6119b2565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c602052604090205460ff168015610f93575073ffffffffffffffffffffffffffffffffffffffff81165f908152609e602052604090205460ff16155b610ff9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d697474657200000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609c6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609d909152902054801561105e5761105e8282611aad565b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a1905f90a25050565b6097545f9073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461113b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6f6e6c7920726f6c6c757020636f6e747261637400000000000000000000000060448201526064016105c1565b611143611a33565b73ffffffffffffffffffffffffffffffffffffffff821661116557505f61128d565b73ffffffffffffffffffffffffffffffffffffffff82165f908152609d602090815260408083208054609c845282852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690915591859055609e84528285208054909216909155609f909252822091909155609a546064906111ec9083612093565b6111f691906120aa565b915061120282826120e2565b609b5f8282546112129190612069565b909155505060975461123a9073ffffffffffffffffffffffffffffffffffffffff1683611c52565b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917f45a371af55b0726877a30f464edc14db5879ab096590bacce682cf6c18223596910160405180910390a2505b6112976001606555565b919050565b6112a46119b2565b6112ac611a33565b73ffffffffffffffffffffffffffffffffffffffff8116611329576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016105c1565b609b5480611393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f20736c6173682072656d61696e696e67000000000000000000000000000060448201526064016105c1565b5f609b556113a18282611c52565b8173ffffffffffffffffffffffffffffffffffffffff167fa1fefb6c5328a92a416e321ed50997303fe7135fd88c28b0592b21ce42b5cdd9826040516113e991815260200190565b60405180910390a250610ac16001606555565b5f54610100900460ff161580801561141a57505f54600160ff909116105b806114335750303b15801561143357505f5460ff166001145b6114bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016105c1565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561151b575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8616611598576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c6964206f776e65720000000000000000000000000000000000000060448201526064016105c1565b73ffffffffffffffffffffffffffffffffffffffff8516158015906115d357505f8573ffffffffffffffffffffffffffffffffffffffff163b115b611639576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f696e76616c696420726f6c6c757020636f6e747261637400000000000000000060448201526064016105c1565b5f84116116a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e76616c6964206d696e696d756d207374616b65000000000000000000000060448201526064016105c1565b5f831161170b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964206368616c6c656e6765206465706f7369740000000000000060448201526064016105c1565b5f8211801561171b575060648211155b611781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e76616c6964207265776172642070657263656e746167650000000000000060448201526064016105c1565b611789611d28565b611791611dc6565b61179a86611bdc565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871617905560988490556099839055609a829055604080515f8152602081018690527fd67ed534faf3e0dcda08ac6043ec96dcf9b6ebec56055fd14bd0cb40a27c0e49910160405180910390a1604080515f8152602081018590527f36f971a40478225aeb80cfbf5e80306e8cb76d3bf7d56fdc5e490945cddb7d55910160405180910390a1604080515f8152602081018490527fa46de936426e045703b2d34a292a19fde92b329018db8e0da750033876b655ba910160405180910390a180156118f6575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6119066119b2565b73ffffffffffffffffffffffffffffffffffffffff81166119a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016105c1565b610ac181611bdc565b60335473ffffffffffffffffffffffffffffffffffffffff163314610987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105c1565b600260655403611a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105c1565b6002606555565b6001606555565b73ffffffffffffffffffffffffffffffffffffffff8083165f908152609e602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560975482517f121dcd50000000000000000000000000000000000000000000000000000000008152925193169263121dcd509260048082019392918290030181865afa158015611b51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b75919061207c565b73ffffffffffffffffffffffffffffffffffffffff83165f818152609f6020526040908190209290925590517fe670e4e82118d22a1f9ee18920455ebc958bae26a90a05d31d3378788b1b0e4490611bd09084815260200190565b60405180910390a25050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b805f03611c5d575050565b5f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114611cb3576040519150601f19603f3d011682016040523d82523d5f602084013e611cb8565b606091505b5050905080611d23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016105c1565b505050565b5f54610100900460ff16611dbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c1565b610987611e64565b5f54610100900460ff16611e5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c1565b610987611f03565b5f54610100900460ff16611efa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c1565b61098733611bdc565b5f54610100900460ff16611aa6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016105c1565b803573ffffffffffffffffffffffffffffffffffffffff81168114611297575f80fd5b5f60208284031215611fcc575f80fd5b611fd582611f99565b9392505050565b5f60208284031215611fec575f80fd5b5035919050565b5f805f805f60a08688031215612007575f80fd5b61201086611f99565b945061201e60208701611f99565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610b6057610b6061203c565b5f6020828403121561208c575f80fd5b5051919050565b8082028115828204841417610b6057610b6061203c565b5f826120dd577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610b6057610b6061203c56fea164736f6c6343000818000a" func init() { if err := json.Unmarshal([]byte(SubmitterStorageLayoutJSON), SubmitterStorageLayout); err != nil { diff --git a/contracts/contracts/l1/rollup/ISubmitter.sol b/contracts/contracts/l1/rollup/ISubmitter.sol index 63e540b89..0285a7abb 100644 --- a/contracts/contracts/l1/rollup/ISubmitter.sol +++ b/contracts/contracts/l1/rollup/ISubmitter.sol @@ -10,7 +10,7 @@ interface ISubmitter { function slash(address submitter) external returns (uint256 reward); } -/// @notice Existing Rollup state used to release all submitter stake after a global drain. +/// @notice Existing Rollup state used to wait for batches that predate a submitter's exit. interface IRollupSubmitterView { function lastCommittedBatchIndex() external view returns (uint256); diff --git a/contracts/contracts/l1/rollup/Submitter.sol b/contracts/contracts/l1/rollup/Submitter.sol index d2a9cd7ef..173ff216c 100644 --- a/contracts/contracts/l1/rollup/Submitter.sol +++ b/contracts/contracts/l1/rollup/Submitter.sol @@ -18,6 +18,7 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable mapping(address submitter => bool isRegistered) public registered; mapping(address submitter => uint256 amount) public stakeOf; mapping(address submitter => bool isWithdrawing) public withdrawing; + mapping(address submitter => uint256 batchIndex) public withdrawalBatchIndex; event SubmitterAdded(address indexed submitter); event SubmitterRemoved(address indexed submitter); @@ -72,10 +73,7 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable function addSubmitter(address submitter) external onlyOwner { require( - submitter != address(0) && - !registered[submitter] && - !withdrawing[submitter] && - stakeOf[submitter] == 0, + submitter != address(0) && !registered[submitter] && !withdrawing[submitter] && stakeOf[submitter] == 0, "invalid submitter" ); registered[submitter] = true; @@ -87,8 +85,7 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable registered[submitter] = false; uint256 amount = stakeOf[submitter]; if (amount > 0) { - withdrawing[submitter] = true; - emit WithdrawalRequested(submitter, amount); + _startWithdrawal(submitter, amount); } emit SubmitterRemoved(submitter); } @@ -126,19 +123,22 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable // Exiting always revokes the owner's previous authorization. Re-entry requires addSubmitter. registered[submitter] = false; - withdrawing[submitter] = true; - emit WithdrawalRequested(submitter, stakeOf[submitter]); + _startWithdrawal(submitter, stakeOf[submitter]); } function claimWithdrawal(address receiver) external nonReentrant { address submitter = _msgSender(); require(receiver != address(0), "invalid receiver"); require(withdrawing[submitter], "not withdrawing"); - require(_isGloballyDrained(), "rollup not drained"); + require( + IRollupSubmitterView(rollupContract).lastFinalizedBatchIndex() >= withdrawalBatchIndex[submitter], + "withdrawal batch not finalized" + ); uint256 amount = stakeOf[submitter]; stakeOf[submitter] = 0; withdrawing[submitter] = false; + delete withdrawalBatchIndex[submitter]; _transfer(receiver, amount); emit WithdrawalClaimed(submitter, receiver, amount); } @@ -150,6 +150,7 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable registered[submitter] = false; stakeOf[submitter] = 0; withdrawing[submitter] = false; + delete withdrawalBatchIndex[submitter]; reward = (amount * rewardPercentage) / 100; slashRemaining += amount - reward; @@ -166,16 +167,17 @@ contract Submitter is ISubmitter, OwnableUpgradeable, ReentrancyGuardUpgradeable emit SlashRemainingClaimed(receiver, amount); } - function _isGloballyDrained() internal view returns (bool) { - IRollupSubmitterView rollup = IRollupSubmitterView(rollupContract); - return rollup.lastCommittedBatchIndex() == rollup.lastFinalizedBatchIndex(); + function _startWithdrawal(address submitter, uint256 amount) internal { + withdrawing[submitter] = true; + withdrawalBatchIndex[submitter] = IRollupSubmitterView(rollupContract).lastCommittedBatchIndex(); + emit WithdrawalRequested(submitter, amount); } function _transfer(address receiver, uint256 amount) internal { if (amount == 0) return; - (bool success, ) = receiver.call{value: amount}(""); + (bool success,) = receiver.call{value: amount}(""); require(success, "ETH transfer failed"); } - uint256[50] private __gap; + uint256[49] private __gap; } diff --git a/contracts/contracts/test/Submitter.t.sol b/contracts/contracts/test/Submitter.t.sol index 51fe94d2b..ab95304b0 100644 --- a/contracts/contracts/test/Submitter.t.sol +++ b/contracts/contracts/test/Submitter.t.sol @@ -7,7 +7,7 @@ import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transpa import {ISubmitter} from "../l1/rollup/ISubmitter.sol"; import {Submitter} from "../l1/rollup/Submitter.sol"; -contract DrainRollupMock { +contract RollupIndexMock { uint256 public lastCommittedBatchIndex; uint256 public lastFinalizedBatchIndex; @@ -39,21 +39,20 @@ contract SubmitterTest is Test { address internal alice = address(0xB0B); address internal bob = address(0xCAFE); - DrainRollupMock internal rollupMock; + RollupIndexMock internal rollupMock; Submitter internal implementation; Submitter internal submitter; function setUp() public { vm.deal(alice, 100 ether); vm.deal(bob, 100 ether); - rollupMock = new DrainRollupMock(); + rollupMock = new RollupIndexMock(); implementation = new Submitter(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), proxyAdmin, abi.encodeCall( - Submitter.initialize, - (owner, address(rollupMock), MINIMUM_STAKE, CHALLENGE_DEPOSIT, REWARD_PERCENTAGE) + Submitter.initialize, (owner, address(rollupMock), MINIMUM_STAKE, CHALLENGE_DEPOSIT, REWARD_PERCENTAGE) ) ); submitter = Submitter(payable(address(proxy))); @@ -99,7 +98,7 @@ contract SubmitterTest is Test { assertTrue(submitter.withdrawing(alice)); } - function test_withdrawWaitsForGlobalDrainAndRequiresOwnerToReauthorize() public { + function test_withdrawWaitsForExitSnapshotAndDoesNotRequireGlobalDrain() public { _registerAndStake(alice); rollupMock.setBatchIndexes(2, 1); @@ -108,18 +107,22 @@ contract SubmitterTest is Test { assertFalse(submitter.isActive(alice)); assertFalse(submitter.registered(alice)); assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + assertEq(submitter.withdrawalBatchIndex(alice), 2); + rollupMock.setBatchIndexes(3, 1); vm.prank(alice); - vm.expectRevert("rollup not drained"); + vm.expectRevert("withdrawal batch not finalized"); submitter.claimWithdrawal(bob); - rollupMock.setBatchIndexes(2, 2); + // Other submitters can keep committing. Only the exit-time snapshot must be finalized. + rollupMock.setBatchIndexes(4, 2); uint256 beforeBalance = bob.balance; vm.prank(alice); submitter.claimWithdrawal(bob); assertEq(bob.balance - beforeBalance, MINIMUM_STAKE); assertEq(submitter.stakeOf(alice), 0); assertFalse(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 0); vm.prank(alice); vm.expectRevert("not stakeable"); @@ -128,7 +131,21 @@ contract SubmitterTest is Test { submitter.addSubmitter(alice); } - function test_ownerRemovalUsesTheSameDrainGate() public { + function test_zeroExitSnapshotCanBeClaimed() public { + _registerAndStake(alice); + + vm.prank(alice); + submitter.withdraw(); + assertTrue(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 0); + + vm.prank(alice); + submitter.claimWithdrawal(alice); + assertFalse(submitter.withdrawing(alice)); + assertEq(submitter.stakeOf(alice), 0); + } + + function test_ownerRemovalUsesTheSameExitSnapshot() public { _registerAndStake(alice); rollupMock.setBatchIndexes(3, 2); @@ -136,16 +153,34 @@ contract SubmitterTest is Test { submitter.removeSubmitter(alice); assertFalse(submitter.registered(alice)); assertTrue(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 3); + // A revert can make the live indexes equal below the recorded exit boundary. + rollupMock.setBatchIndexes(2, 2); vm.prank(alice); - vm.expectRevert("rollup not drained"); + vm.expectRevert("withdrawal batch not finalized"); submitter.claimWithdrawal(alice); assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); + assertEq(submitter.withdrawalBatchIndex(alice), 3); - rollupMock.setBatchIndexes(3, 3); + rollupMock.setBatchIndexes(5, 4); vm.prank(alice); submitter.claimWithdrawal(alice); assertEq(submitter.stakeOf(alice), 0); + assertEq(submitter.withdrawalBatchIndex(alice), 0); + } + + function test_ownerRemovalWithoutStakeLeavesNoWithdrawalSnapshot() public { + vm.prank(owner); + submitter.addSubmitter(alice); + rollupMock.setBatchIndexes(7, 5); + + vm.prank(owner); + submitter.removeSubmitter(alice); + + assertFalse(submitter.registered(alice)); + assertFalse(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 0); } function test_exitingStakeRemainsSlashable() public { @@ -162,6 +197,7 @@ contract SubmitterTest is Test { assertEq(submitter.stakeOf(alice), 0); assertFalse(submitter.registered(alice)); assertFalse(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 0); vm.prank(owner); submitter.addSubmitter(alice); @@ -187,6 +223,7 @@ contract SubmitterTest is Test { function test_failedWithdrawalTransferPreservesStakeAndExit() public { _registerAndStake(alice); + rollupMock.setBatchIndexes(2, 2); vm.prank(alice); submitter.withdraw(); RejectEther receiver = new RejectEther(); @@ -196,6 +233,7 @@ contract SubmitterTest is Test { submitter.claimWithdrawal(address(receiver)); assertEq(submitter.stakeOf(alice), MINIMUM_STAKE); assertTrue(submitter.withdrawing(alice)); + assertEq(submitter.withdrawalBatchIndex(alice), 2); } function _registerAndStake(address account) internal { From 302221e6b213392262b391886fa5ded8261fa781 Mon Sep 17 00:00:00 2001 From: Segue Date: Mon, 17 Aug 2026 07:22:27 +0800 Subject: [PATCH 32/38] test(selector): cover service cutover boundaries --- common/batch/selector_boundary_test.go | 60 +++++ gas-oracle/app/src/da_scalar/l1_scalar.rs | 49 +++- gas-oracle/app/src/gas_price_oracle.rs | 62 ++++- node/derivation/selector_cursor_test.go | 242 ++++++++++++++++++ .../bin/challenge/src/bin/auto_challenge.rs | 43 +++- prover/bin/challenge/src/handler.rs | 19 +- prover/bin/shadow-prove/src/abi.rs | 68 +++++ prover/bin/shadow-prove/src/shadow_rollup.rs | 36 ++- 8 files changed, 548 insertions(+), 31 deletions(-) create mode 100644 common/batch/selector_boundary_test.go create mode 100644 node/derivation/selector_cursor_test.go diff --git a/common/batch/selector_boundary_test.go b/common/batch/selector_boundary_test.go new file mode 100644 index 000000000..1e2603a90 --- /dev/null +++ b/common/batch/selector_boundary_test.go @@ -0,0 +1,60 @@ +package batch + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestProductionCodeDoesNotCallCompactCommitParser(t *testing.T) { + packageDir, err := os.Getwd() + require.NoError(t, err) + + entries, err := os.ReadDir(packageDir) + require.NoError(t, err) + + files := token.NewFileSet() + var references []string + for _, entry := range entries { + name := entry.Name() + if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { + continue + } + + path := filepath.Join(packageDir, name) + file, err := parser.ParseFile(files, path, nil, 0) + require.NoError(t, err, "parse production source %s", name) + + definitions := make(map[token.Pos]struct{}) + for _, declaration := range file.Decls { + function, ok := declaration.(*ast.FuncDecl) + if ok && function.Name.Name == "parseCommitBatchTxData" { + definitions[function.Name.Pos()] = struct{}{} + } + } + + ast.Inspect(file, func(node ast.Node) bool { + identifier, ok := node.(*ast.Ident) + if !ok || identifier.Name != "parseCommitBatchTxData" { + return true + } + if _, isDefinition := definitions[identifier.Pos()]; isDefinition { + return true + } + + position := files.Position(identifier.Pos()) + references = append(references, fmt.Sprintf("%s:%d", filepath.Base(position.Filename), position.Line)) + return true + }) + } + + require.Empty(t, references, + "production batch code must not reference the test-only compact commit parser") +} diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index f10928cdb..5772e262c 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -25,6 +25,16 @@ const PRECISION: u64 = 10u64.pow(9); const MAX_COMMIT_SCALAR: u64 = 10u64.pow(9 + 6); const MAX_BLOB_SCALAR: u64 = 10u64.pow(9 + 2); +fn select_blob_sample_calldata(blob_hash_count: usize, tx_input: &[u8]) -> Option<&[u8]> { + (blob_hash_count > 0).then_some(tx_input) +} + +fn decode_selected_blob_sample_last_block_number( + selected_calldata: Option<&[u8]>, +) -> eyre::Result> { + selected_calldata.map(decode_commit_batch_last_block_number).transpose() +} + // Main struct to manage overhead information pub struct ScalarUpdater { l1_provider: Provider, // L1 provider for HTTP connections @@ -298,10 +308,12 @@ impl ScalarUpdater { })?; let indexed_hashes = data_and_hashes_from_txs(&blob_block.transactions, &blob_tx); - if indexed_hashes.is_empty() { + let selected_calldata = + select_blob_sample_calldata(indexed_hashes.len(), blob_tx.input.as_ref()); + let Some(selected_calldata) = selected_calldata else { log::info!("no blob in this batch, batch_tx_hash: {:#?}", tx_hash); return Ok((0, 0, 0)); - } + }; // Waiting for the next L1 block to be produced. let next_block_num = block_num + 1; @@ -337,18 +349,21 @@ impl ScalarUpdater { }; // Parse last_block_num - if blob_tx.input.is_empty() { + if selected_calldata.is_empty() { log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", tx_hash); return Err(ScalarError::Error(anyhow!(format!("commitBatch tx.input empty")))); } - let last_block_num = if let Ok(last_block_num) = - decode_commit_batch_last_block_number(&blob_tx.input) - { - last_block_num - } else { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); - return Err(ScalarError::Error(anyhow!(format!("decode commitBatch tx.input error",)))); - }; + let last_block_num = + match decode_selected_blob_sample_last_block_number(Some(selected_calldata)) { + Ok(Some(last_block_num)) => last_block_num, + Ok(None) => unreachable!("blob sample calldata was selected above"), + Err(_) => { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); + return Err(ScalarError::Error(anyhow!(format!( + "decode commitBatch tx.input error", + )))); + } + }; let indexes: Vec = indexed_hashes.iter().map(|item| item.index).collect(); let sidecars_rt = self @@ -390,6 +405,18 @@ mod tests { use super::*; use std::{env::var, str::FromStr, sync::Arc}; + #[test] + fn no_blob_sample_skips_selector_decoding() { + let unknown_selector = [0xde, 0xad, 0xbe, 0xef]; + + let no_blob_calldata = select_blob_sample_calldata(0, &unknown_selector); + assert!(no_blob_calldata.is_none()); + assert_eq!(decode_selected_blob_sample_last_block_number(no_blob_calldata).unwrap(), None); + + let blob_calldata = select_blob_sample_calldata(1, &unknown_selector); + assert!(decode_selected_blob_sample_last_block_number(blob_calldata).is_err()); + } + #[tokio::test] #[ignore] async fn test_calculate_from_current_rollup() { diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index 74655abb3..d93576f0a 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -4,7 +4,6 @@ use crate::{ l1_base_fee::BaseFeeUpdater, read_parse_env, }; -use remote_signer_client::SignerClient; use ethers::{ prelude::*, providers::{Http, Provider}, @@ -12,6 +11,7 @@ use ethers::{ types::Address, }; use eyre::anyhow; +use remote_signer_client::SignerClient; use std::{env::var, error::Error, str::FromStr, sync::Arc, time::Duration}; use tokio::time::sleep; @@ -24,6 +24,37 @@ use crate::{metrics::*, read_env_var}; const DEFAULT_PRIVATE_KEY: &str = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +#[derive(Clone, Copy)] +enum ScalarUpdateStage { + Startup, + Periodic, +} + +#[derive(Debug, Eq, PartialEq)] +enum ScalarUpdateOutcome { + Applied, + SkippedAfterError, +} + +fn handle_scalar_update_result( + stage: ScalarUpdateStage, + result: Result<(), E>, +) -> ScalarUpdateOutcome { + match stage { + ScalarUpdateStage::Startup => { + result.expect("overhead_update err"); + ScalarUpdateOutcome::Applied + } + ScalarUpdateStage::Periodic => match result { + Ok(()) => ScalarUpdateOutcome::Applied, + Err(e) => { + log::error!("overhead_updater err: {:?}", e); + ScalarUpdateOutcome::SkippedAfterError + } + }, + } +} + struct Config { l1_rpc: String, l2_rpc: String, @@ -135,7 +166,7 @@ async fn start_updater( mut scalar_updater: ScalarUpdater, ) { base_fee_updater.update().await.expect("base_fee_update err"); - scalar_updater.update().await.expect("overhead_update err"); + handle_scalar_update_result(ScalarUpdateStage::Startup, scalar_updater.update().await); tokio::spawn(async move { let mut update_times = 0; @@ -154,10 +185,7 @@ async fn start_updater( } // Waiting for confirmation of the previous transaction. sleep(Duration::from_millis(6000)).await; - let _ = scalar_updater - .update() - .await - .map_err(|e| log::error!("overhead_updater err: {:?}", e)); + handle_scalar_update_result(ScalarUpdateStage::Periodic, scalar_updater.update().await); update_times = 0 } }); @@ -277,6 +305,28 @@ async fn handle_metrics() -> String { #[cfg(test)] mod tests { use super::*; + use std::panic::catch_unwind; + + fn unknown_selector_error() -> eyre::Error { + crate::abi::decode_commit_batch_last_block_number(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err() + } + + #[test] + fn startup_scalar_update_panics_on_unknown_selector_error() { + let panic = catch_unwind(|| { + handle_scalar_update_result(ScalarUpdateStage::Startup, Err(unknown_selector_error())) + }); + + assert!(panic.is_err()); + } + + #[test] + fn periodic_scalar_update_skips_unknown_selector_error() { + let outcome = + handle_scalar_update_result(ScalarUpdateStage::Periodic, Err(unknown_selector_error())); + + assert_eq!(outcome, ScalarUpdateOutcome::SkippedAfterError); + } #[tokio::test(flavor = "multi_thread", worker_threads = 4)] #[ignore] diff --git a/node/derivation/selector_cursor_test.go b/node/derivation/selector_cursor_test.go new file mode 100644 index 000000000..3bb16a501 --- /dev/null +++ b/node/derivation/selector_cursor_test.go @@ -0,0 +1,242 @@ +package derivation + +import ( + "context" + "encoding/json" + "math/big" + "testing" + + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + eth "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" + "github.com/morph-l2/go-ethereum/ethclient" + "github.com/morph-l2/go-ethereum/rpc" + "github.com/stretchr/testify/require" + tmlog "github.com/tendermint/tendermint/libs/log" + + "morph-l2/bindings/bindings" + nodedb "morph-l2/node/db" + nodetypes "morph-l2/node/types" +) + +const selectorCursorTestL1Height = uint64(42) + +// selectorCursorTestDB is the smallest in-memory implementation needed to +// observe whether derivationBlock committed its L1 scan cursor. The L1 message +// methods are unused by these tests but are required by Database. +type selectorCursorTestDB struct { + latestDerivation *uint64 + derivationBlocks map[uint64]*nodedb.DerivationL1Block +} + +func newSelectorCursorTestDB() *selectorCursorTestDB { + return &selectorCursorTestDB{derivationBlocks: make(map[uint64]*nodedb.DerivationL1Block)} +} + +func (db *selectorCursorTestDB) ReadLatestDerivationL1Height() *uint64 { + if db.latestDerivation == nil { + return nil + } + value := *db.latestDerivation + return &value +} + +func (db *selectorCursorTestDB) WriteLatestDerivationL1Height(latest uint64) { + db.latestDerivation = new(uint64) + *db.latestDerivation = latest +} + +func (db *selectorCursorTestDB) ReadDerivationL1BlockRange(from, to uint64) []*nodedb.DerivationL1Block { + if from > to { + return nil + } + blocks := make([]*nodedb.DerivationL1Block, 0, to-from+1) + for height := from; height <= to; height++ { + if block := db.derivationBlocks[height]; block != nil { + copy := *block + blocks = append(blocks, ©) + } + } + return blocks +} + +func (db *selectorCursorTestDB) WriteDerivationL1Block(block *nodedb.DerivationL1Block) { + copy := *block + db.derivationBlocks[block.Number] = © +} + +func (db *selectorCursorTestDB) DeleteDerivationL1BlocksFrom(height uint64) { + for number := range db.derivationBlocks { + if number >= height { + delete(db.derivationBlocks, number) + } + } +} + +func (*selectorCursorTestDB) ReadLatestSyncedL1Height() *uint64 { return nil } + +func (*selectorCursorTestDB) ReadL1MessagesInRange(uint64, uint64) []nodetypes.L1Message { + return nil +} + +func (*selectorCursorTestDB) ReadL1MessageByIndex(uint64) *nodetypes.L1Message { return nil } + +func (*selectorCursorTestDB) WriteLatestSyncedL1Height(uint64) {} + +func (*selectorCursorTestDB) WriteSyncedL1Messages([]nodetypes.L1Message, uint64) error { + return nil +} + +// selectorCursorEthAPI provides the exact JSON-RPC surface derivationBlock +// reaches before it either skips an unknown selector or aborts on malformed +// calldata. +type selectorCursorEthAPI struct { + tx *eth.Transaction + from common.Address + rollupAddress common.Address + header *eth.Header +} + +func (api *selectorCursorEthAPI) BlockNumber(context.Context) (hexutil.Uint64, error) { + return hexutil.Uint64(selectorCursorTestL1Height), nil +} + +func (api *selectorCursorEthAPI) GetLogs(context.Context, map[string]interface{}) ([]eth.Log, error) { + return []eth.Log{{ + Address: api.rollupAddress, + Topics: []common.Hash{RollupEventTopicHash}, + TxHash: api.tx.Hash(), + BlockHash: api.header.Hash(), + BlockNumber: selectorCursorTestL1Height, + }}, nil +} + +func (*selectorCursorEthAPI) Call(context.Context, map[string]interface{}, string) (hexutil.Bytes, error) { + // Rollup.lastCommittedBatchIndex() == 1. + return common.LeftPadBytes([]byte{1}, 32), nil +} + +func (api *selectorCursorEthAPI) GetTransactionByHash(context.Context, common.Hash) (json.RawMessage, error) { + raw, err := api.tx.MarshalJSON() + if err != nil { + return nil, err + } + var fields map[string]interface{} + if err := json.Unmarshal(raw, &fields); err != nil { + return nil, err + } + fields["blockNumber"] = hexutil.EncodeUint64(selectorCursorTestL1Height) + fields["blockHash"] = api.header.Hash() + fields["from"] = api.from + return json.Marshal(fields) +} + +func (api *selectorCursorEthAPI) GetBlockByNumber(context.Context, string, bool) (*eth.Header, error) { + return api.header, nil +} + +func TestDerivationBlockSelectorErrorControlsCursorAdvance(t *testing.T) { + verifyModes := []string{VerifyModeLayer1, VerifyModeLocal} + tests := []struct { + name string + calldata []byte + wantAdvance bool + }{ + { + name: "unknown selector is skipped and successful poll advances cursor", + calldata: []byte{0xde, 0xad, 0xbe, 0xef}, + wantAdvance: true, + }, + { + name: "known selector with malformed calldata aborts poll without cursor advance", + calldata: []byte{0x41, 0xf7, 0x56, 0xda}, + wantAdvance: false, + }, + } + + for _, verifyMode := range verifyModes { + for _, test := range tests { + t.Run(verifyMode+"/"+test.name, func(t *testing.T) { + d, db := newSelectorCursorTestDerivation(t, verifyMode, test.calldata) + + d.derivationBlock(context.Background()) + + cursor := db.ReadLatestDerivationL1Height() + if test.wantAdvance { + require.NotNil(t, cursor) + require.Equal(t, selectorCursorTestL1Height, *cursor) + require.Contains(t, db.derivationBlocks, selectorCursorTestL1Height, + "a successful poll records the scanned L1 block before advancing") + } else { + require.Nil(t, cursor) + require.Empty(t, db.derivationBlocks, + "an aborted poll must not record the range it did not commit") + } + }) + } + } +} + +func newSelectorCursorTestDerivation( + t *testing.T, + verifyMode string, + calldata []byte, +) (*Derivation, *selectorCursorTestDB) { + t.Helper() + + key, err := crypto.GenerateKey() + require.NoError(t, err) + from := crypto.PubkeyToAddress(key.PublicKey) + rollupAddress := common.HexToAddress("0x1000000000000000000000000000000000000001") + unsigned := eth.NewTransaction( + 0, + rollupAddress, + big.NewInt(0), + 100_000, + big.NewInt(1), + calldata, + ) + tx, err := eth.SignTx(unsigned, eth.NewEIP155Signer(big.NewInt(1)), key) + require.NoError(t, err) + + header := ð.Header{ + Number: new(big.Int).SetUint64(selectorCursorTestL1Height), + Difficulty: big.NewInt(0), + GasLimit: 30_000_000, + Time: 1, + Extra: []byte{}, + } + server := rpc.NewServer() + require.NoError(t, server.RegisterName("eth", &selectorCursorEthAPI{ + tx: tx, + from: from, + rollupAddress: rollupAddress, + header: header, + })) + rpcClient := rpc.DialInProc(server) + t.Cleanup(rpcClient.Close) + t.Cleanup(server.Stop) + l1Client := ethclient.NewClient(rpcClient) + + rollup, err := bindings.NewRollup(rollupAddress, l1Client) + require.NoError(t, err) + db := newSelectorCursorTestDB() + logger := tmlog.NewNopLogger() + d := newFixtureDerivation(t) + d.ctx = context.Background() + d.db = db + d.l1Client = l1Client + d.RollupContractAddress = rollupAddress + d.confirmations = rpc.LatestBlockNumber + d.l2Client = nodetypes.NewRetryableClient(nil, l1Client, logger) + d.logger = logger + d.rollup = rollup + d.metrics = newDiscardMetrics() + d.startHeight = selectorCursorTestL1Height + d.fetchBlockRange = 100 + d.verifyMode = verifyMode + d.reorgCheckDepth = 10 + + return d, db +} diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index 5c100b9f4..6d7930ffe 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -121,9 +121,8 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi return Ok(()); } - logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); - let batch_index = match logs.get(logs.len() - 2) { - Some(log) => log.topics[1].to_low_u64_be(), + let batch_index = match candidate_batch_index_from_events(&mut logs) { + Some(batch_index) => batch_index, None => { log::error!("find commit_batch log error"); return Ok(()); @@ -202,6 +201,13 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi Ok(()) } +/// Select the penultimate committed batch using event metadata only. Deliberately accepting +/// `Log` values rather than transactions keeps auto-challenge independent of commit calldata. +fn candidate_batch_index_from_events(logs: &mut [Log]) -> Option { + logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); + logs.get(logs.len() - 2).map(|log| log.topics[1].to_low_u64_be()) +} + async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Provider) -> Option { let start = if latest > U64::from(7200) { // Depends on proof window @@ -250,3 +256,34 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr async fn verify_state_transition() { // Do nothing } + +#[cfg(test)] +mod tests { + use super::*; + + fn commit_batch_event(block_number: u64, batch_index: u64) -> Log { + Log { + block_number: Some(block_number.into()), + topics: vec![H256::zero(), H256::from_low_u64_be(batch_index)], + ..Default::default() + } + } + + #[test] + fn selects_candidate_from_event_metadata_without_a_transaction_hash() { + let mut logs = vec![commit_batch_event(12, 42), commit_batch_event(10, 40), commit_batch_event(11, 41)]; + assert!(logs.iter().all(|log| log.transaction_hash.is_none())); + + assert_eq!(candidate_batch_index_from_events(&mut logs), Some(41)); + } + + #[test] + fn source_has_no_commit_transaction_lookup_or_calldata_decoder() { + let source = include_str!("auto_challenge.rs"); + let transaction_lookup = ["get_", "transaction"].concat(); + let commit_decoder = ["decode_", "commit_batch"].concat(); + + assert!(!source.contains(&transaction_lookup)); + assert!(!source.contains(&commit_decoder)); + } +} diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 32d4acbe6..54b709854 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -435,7 +435,7 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide return None; } }; - if batch_in_challenge && !is_batch_finalized { + if should_read_commit_calldata(batch_in_challenge, is_batch_finalized) { return Some(batch_index); } log::debug!("batch status not in challenge or already finalized, batch index = {:#?}", batch_index); @@ -444,6 +444,13 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide None } +/// Commit calldata is only needed after the on-chain status checks identify a live challenge. +/// In particular, batches finalized before the strict upgrade cutover must not reach the +/// transaction lookup and calldata decoder in `handle_with_prover`. +fn should_read_commit_calldata(batch_in_challenge: bool, is_batch_finalized: bool) -> bool { + batch_in_challenge && !is_batch_finalized +} + #[derive(Default, Clone)] struct BatchInfo { version: u8, @@ -636,6 +643,16 @@ mod tests { mock.push::(Bytes::from(encode(&[token]))).unwrap(); } + #[test] + fn strict_upgrade_state_closes_calldata_gate_for_finalized_legacy_batches() { + // initialize4 requires no live challenge and all committed batches to be finalized. + assert!(!should_read_commit_calldata(false, true)); + // Even a stale challenge event cannot make a finalized batch reach calldata lookup. + assert!(!should_read_commit_calldata(true, true)); + assert!(!should_read_commit_calldata(false, false)); + assert!(should_read_commit_calldata(true, false)); + } + #[tokio::test] async fn accepts_active_signer() { let (rollup, mock, _, submitter_address) = mock_rollup(); diff --git a/prover/bin/shadow-prove/src/abi.rs b/prover/bin/shadow-prove/src/abi.rs index 6d07b05c8..31c73095a 100644 --- a/prover/bin/shadow-prove/src/abi.rs +++ b/prover/bin/shadow-prove/src/abi.rs @@ -23,6 +23,20 @@ pub struct CommitBatchInput { pub last_block_number: u64, } +/// Derive the target batch's L2 block range from the previous and target commits. +pub fn target_batch_block_range( + previous: &CommitBatchInput, + target: &CommitBatchInput, +) -> (u64, u64) { + (previous.last_block_number + 1, target.last_block_number) +} + +/// A commit carries its parent's header, so the commit after the target is the source of the +/// target batch header. +pub fn target_batch_header_from_next_commit(next: &CommitBatchInput) -> Bytes { + next.parent_batch_header.clone() +} + /// Decode the pre- or post-upgrade commitBatch calldata handled by shadow-prove. pub fn decode_commit_batch(data: &[u8]) -> Result { let selector = @@ -61,6 +75,7 @@ sol!( #[cfg(test)] mod tests { use super::*; + use alloy_primitives::{B256, U256}; const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; @@ -69,6 +84,41 @@ mod tests { alloy_primitives::hex::decode(value.trim_start_matches("0x")).unwrap() } + fn post_submitter_commit_batch(parent_batch_header: &[u8], last_block_number: u64) -> Vec { + Rollup::commitBatchCall { + batchDataInput: IRollup::BatchDataInput { + version: 2, + parentBatchHeader: Bytes::copy_from_slice(parent_batch_header), + lastBlockNumber: last_block_number, + numL1Messages: 0, + prevStateRoot: B256::ZERO, + postStateRoot: B256::ZERO, + withdrawalRoot: B256::ZERO, + }, + } + .abi_encode() + } + + fn pre_submitter_commit_batch(parent_batch_header: &[u8], last_block_number: u64) -> Vec { + PreSubmitterRollup::commitBatchCall { + batchDataInput: pre_submitter::IRollup::BatchDataInput { + version: 2, + parentBatchHeader: Bytes::copy_from_slice(parent_batch_header), + lastBlockNumber: last_block_number, + numL1Messages: 0, + prevStateRoot: B256::ZERO, + postStateRoot: B256::ZERO, + withdrawalRoot: B256::ZERO, + }, + batchSignatureInput: pre_submitter::IRollup::BatchSignatureInput { + signedSequencersBitmap: U256::ZERO, + sequencerSets: Bytes::new(), + signature: Bytes::new(), + }, + } + .abi_encode() + } + #[test] fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { let pre = decode_commit_batch(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(); @@ -89,4 +139,22 @@ mod tests { assert!(decode_commit_batch(&[0x15, 0x44, 0xba, 0x3a]).is_err()); assert!(decode_commit_batch(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); } + + #[test] + fn decodes_and_assembles_old_new_new_cutover_window() { + let old_calldata = pre_submitter_commit_batch(b"old-parent", 99); + let target_calldata = post_submitter_commit_batch(b"target-parent", 109); + let next_calldata = post_submitter_commit_batch(b"target-header", 119); + assert_eq!(&old_calldata[..4], PreSubmitterRollup::commitBatchCall::SELECTOR); + assert_eq!(&target_calldata[..4], Rollup::commitBatchCall::SELECTOR); + assert_eq!(&next_calldata[..4], Rollup::commitBatchCall::SELECTOR); + + let old = decode_commit_batch(&old_calldata).unwrap(); + let target = decode_commit_batch(&target_calldata).unwrap(); + let next = decode_commit_batch(&next_calldata).unwrap(); + + assert_eq!(target_batch_block_range(&old, &target), (100, 109)); + assert_eq!(target_batch_header_from_next_commit(&next).as_ref(), b"target-header"); + assert_ne!(target.parent_batch_header, target_batch_header_from_next_commit(&next)); + } } diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index b70610623..bbde33794 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -1,4 +1,11 @@ -use crate::{abi::decode_commit_batch, metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; +use crate::{ + abi::{ + decode_commit_batch, target_batch_block_range, target_batch_header_from_next_commit, + CommitBatchInput, + }, + metrics::METRICS, + BatchInfo, SHADOW_PROVING_BLOCKS_RANGE, +}; use alloy_consensus::Transaction; use alloy_network::{Network, ReceiptResponse}; use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256, U64}; @@ -163,12 +170,12 @@ where return Err(anyhow!("find commit_batch log error")); } }; - let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) + let batch_input = commit_batch_input_inspect(&self.l1_provider, next_tx_hash) .await .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; log::info!("Found the committed batch, batch index = {:#?}", batch_index_hash.0); - Ok(Some((batch_info, batch_input.0))) + Ok(Some((batch_info, target_batch_header_from_next_commit(&batch_input)))) } /// Fetch a specified batch from l1-rollup by batch_num. @@ -320,12 +327,12 @@ where }; // next(batch_num+1) commitBatch calldata contains curr(batch_num) parentBatchHeader. - let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) + let batch_input = commit_batch_input_inspect(&self.l1_provider, next_tx_hash) .await .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; log::info!("Found the specified batch (prev/curr/next): {:?}", batch_index_hash); - Ok(Some((batch_info, batch_input.0))) + Ok(Some((batch_info, target_batch_header_from_next_commit(&batch_input)))) } /** @@ -416,11 +423,12 @@ where prev_batch_hash: TxHash, current_batch_hash: TxHash, ) -> Option<((u64, u64), u64)> { - let prev_batch_input = batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; + let prev_batch_input = + commit_batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; let current_batch_input = - batch_input_inspect(&self.l1_provider, current_batch_hash).await?; - let start_block = prev_batch_input.1 + 1; - let end_block = current_batch_input.1; + commit_batch_input_inspect(&self.l1_provider, current_batch_hash).await?; + let (start_block, end_block) = + target_batch_block_range(&prev_batch_input, ¤t_batch_input); if start_block == 0 { log::error!("batch_blocks_inspect: start_block = 0, tx_hash = {:#?}", prev_batch_hash); @@ -510,7 +518,10 @@ where } } -pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Option<(Bytes, u64)> { +async fn commit_batch_input_inspect( + l1_provider: &DynProvider, + hash: TxHash, +) -> Option { //Step1. Get transaction let result = l1_provider.get_transaction_by_hash(hash).await; let tx = match result { @@ -538,6 +549,11 @@ pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Opt log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); return None; }; + Some(input) +} + +pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Option<(Bytes, u64)> { + let input = commit_batch_input_inspect(l1_provider, hash).await?; Some((input.parent_batch_header, input.last_block_number)) } #[tokio::test] From ec261f021efc63eda2ee93ab7adab1ec5d8156a4 Mon Sep 17 00:00:00 2001 From: kathy <22675649+anylots@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:57:19 +0800 Subject: [PATCH 33/38] revert gas-oracle&prover change --- gas-oracle/app/src/abi/Rollup.json | 269 +--- gas-oracle/app/src/abi/mod.rs | 62 - .../app/src/abi/pre_submitter/Rollup.json | 1416 ----------------- gas-oracle/app/src/da_scalar/l1_scalar.rs | 54 +- gas-oracle/app/src/gas_price_oracle.rs | 62 +- prover/README.md | 5 +- prover/bin/challenge/src/abi/Rollup.json | 269 +--- prover/bin/challenge/src/abi/Submitter.json | 21 - prover/bin/challenge/src/abi/mod.rs | 93 -- .../src/abi/pre_submitter/Rollup.json | 1416 ----------------- .../bin/challenge/src/bin/auto_challenge.rs | 43 +- prover/bin/challenge/src/handler.rs | 197 +-- prover/bin/challenge/src/main.rs | 8 +- prover/bin/client/elf/verifier-client | Bin 6900720 -> 6896208 bytes prover/bin/server/src/queue.rs | 30 +- prover/bin/shadow-prove/abi/Rollup.json | 177 +-- .../abi/pre_submitter/Rollup.json | 1416 ----------------- prover/bin/shadow-prove/contracts/README.md | 8 +- prover/bin/shadow-prove/src/abi.rs | 142 +- prover/bin/shadow-prove/src/execute.rs | 2 + prover/bin/shadow-prove/src/shadow_rollup.rs | 85 +- prover/contracts/README.md | 4 +- prover/crates/executor/client/src/lib.rs | 2 +- .../crates/executor/client/src/types/batch.rs | 59 +- .../client/src/verifier/evm_verifier.rs | 12 +- prover/crates/executor/host/src/execute.rs | 12 +- prover/crates/primitives/src/predeployed.rs | 6 + 27 files changed, 256 insertions(+), 5614 deletions(-) delete mode 100644 gas-oracle/app/src/abi/pre_submitter/Rollup.json delete mode 100644 prover/bin/challenge/src/abi/Submitter.json delete mode 100644 prover/bin/challenge/src/abi/pre_submitter/Rollup.json delete mode 100644 prover/bin/shadow-prove/abi/pre_submitter/Rollup.json diff --git a/gas-oracle/app/src/abi/Rollup.json b/gas-oracle/app/src/abi/Rollup.json index 24828973e..28f7a5c6d 100644 --- a/gas-oracle/app/src/abi/Rollup.json +++ b/gas-oracle/app/src/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -325,25 +306,6 @@ "name": "UpdateProofWindow", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +364,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +441,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,121 +637,33 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ + }, { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "signature", "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" } ], - "name": "commitState", + "name": "commitBatch", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -924,7 +779,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -971,32 +826,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +864,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1126,24 +968,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proveRemaining", @@ -1226,19 +1050,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1252,19 +1063,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1317,19 +1115,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/gas-oracle/app/src/abi/mod.rs b/gas-oracle/app/src/abi/mod.rs index 77ec97a97..fdcc9a2c2 100644 --- a/gas-oracle/app/src/abi/mod.rs +++ b/gas-oracle/app/src/abi/mod.rs @@ -4,9 +4,6 @@ //! on the abigen macro. #![allow(missing_docs)] -use ethers::{abi::AbiDecode, contract::EthCall}; -use eyre::{eyre, Result}; - pub mod gas_price_oracle_abi { use ethers::prelude::abigen; abigen!(GasPriceOracle, "src/abi/GasPriceOracle.json"); @@ -16,62 +13,3 @@ pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } - -pub mod pre_submitter_rollup_abi { - use ethers::prelude::abigen; - abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); -} - -/// Decode the last block number from the pre- or post-upgrade commitBatch calldata. -pub fn decode_commit_batch_last_block_number(data: &[u8]) -> Result { - use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; - use rollup_abi::CommitBatchCall; - - let selector = - data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; - if selector == CommitBatchCall::selector() { - return Ok(CommitBatchCall::decode(data)?.batch_data_input.last_block_number); - } - if selector == PreSubmitterCommitBatchCall::selector() { - return Ok(PreSubmitterCommitBatchCall::decode(data)?.batch_data_input.last_block_number); - } - - Err(eyre!("unsupported rollup calldata selector")) -} - -#[cfg(test)] -mod tests { - use super::*; - use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; - use rollup_abi::CommitBatchCall; - - const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; - const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; - - fn calldata(value: &str) -> Vec { - ethers::utils::hex::decode(value.trim_start_matches("0x")).unwrap() - } - - #[test] - fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { - assert_eq!( - decode_commit_batch_last_block_number(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(), - 12_345 - ); - assert_eq!( - decode_commit_batch_last_block_number(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(), - 12_345 - ); - assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); - assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); - } - - #[test] - fn rejects_non_commit_batch_calldata() { - assert!(decode_commit_batch_last_block_number(&[]).is_err()); - assert!(decode_commit_batch_last_block_number(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - assert!(decode_commit_batch_last_block_number(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); - assert!(decode_commit_batch_last_block_number(&[0x15, 0x44, 0xba, 0x3a]).is_err()); - assert!(decode_commit_batch_last_block_number(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); - } -} diff --git a/gas-oracle/app/src/abi/pre_submitter/Rollup.json b/gas-oracle/app/src/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/gas-oracle/app/src/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index 5772e262c..bbd6d8e7a 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -11,13 +11,13 @@ use super::{ }; use crate::{ abi::{ - decode_commit_batch_last_block_number, gas_price_oracle_abi::GasPriceOracle, - rollup_abi::Rollup, + gas_price_oracle_abi::GasPriceOracle, + rollup_abi::{CommitBatchCall, Rollup}, }, metrics::ORACLE_SERVICE_METRICS, signer::send_transaction, }; -use ethers::{prelude::*, utils::hex}; +use ethers::{abi::AbiDecode, prelude::*, utils::hex}; use remote_signer_client::SignerClient; use serde_json::Value; @@ -25,16 +25,6 @@ const PRECISION: u64 = 10u64.pow(9); const MAX_COMMIT_SCALAR: u64 = 10u64.pow(9 + 6); const MAX_BLOB_SCALAR: u64 = 10u64.pow(9 + 2); -fn select_blob_sample_calldata(blob_hash_count: usize, tx_input: &[u8]) -> Option<&[u8]> { - (blob_hash_count > 0).then_some(tx_input) -} - -fn decode_selected_blob_sample_last_block_number( - selected_calldata: Option<&[u8]>, -) -> eyre::Result> { - selected_calldata.map(decode_commit_batch_last_block_number).transpose() -} - // Main struct to manage overhead information pub struct ScalarUpdater { l1_provider: Provider, // L1 provider for HTTP connections @@ -308,12 +298,10 @@ impl ScalarUpdater { })?; let indexed_hashes = data_and_hashes_from_txs(&blob_block.transactions, &blob_tx); - let selected_calldata = - select_blob_sample_calldata(indexed_hashes.len(), blob_tx.input.as_ref()); - let Some(selected_calldata) = selected_calldata else { + if indexed_hashes.is_empty() { log::info!("no blob in this batch, batch_tx_hash: {:#?}", tx_hash); return Ok((0, 0, 0)); - }; + } // Waiting for the next L1 block to be produced. let next_block_num = block_num + 1; @@ -349,21 +337,17 @@ impl ScalarUpdater { }; // Parse last_block_num - if selected_calldata.is_empty() { + if blob_tx.input.is_empty() { log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", tx_hash); return Err(ScalarError::Error(anyhow!(format!("commitBatch tx.input empty")))); } - let last_block_num = - match decode_selected_blob_sample_last_block_number(Some(selected_calldata)) { - Ok(Some(last_block_num)) => last_block_num, - Ok(None) => unreachable!("blob sample calldata was selected above"), - Err(_) => { - log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); - return Err(ScalarError::Error(anyhow!(format!( - "decode commitBatch tx.input error", - )))); - } - }; + let param = if let Ok(_param) = CommitBatchCall::decode(&blob_tx.input) { + _param + } else { + log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", tx_hash); + return Err(ScalarError::Error(anyhow!(format!("decode commitBatch tx.input error",)))); + }; + let last_block_num: u64 = param.batch_data_input.last_block_number; let indexes: Vec = indexed_hashes.iter().map(|item| item.index).collect(); let sidecars_rt = self @@ -405,18 +389,6 @@ mod tests { use super::*; use std::{env::var, str::FromStr, sync::Arc}; - #[test] - fn no_blob_sample_skips_selector_decoding() { - let unknown_selector = [0xde, 0xad, 0xbe, 0xef]; - - let no_blob_calldata = select_blob_sample_calldata(0, &unknown_selector); - assert!(no_blob_calldata.is_none()); - assert_eq!(decode_selected_blob_sample_last_block_number(no_blob_calldata).unwrap(), None); - - let blob_calldata = select_blob_sample_calldata(1, &unknown_selector); - assert!(decode_selected_blob_sample_last_block_number(blob_calldata).is_err()); - } - #[tokio::test] #[ignore] async fn test_calculate_from_current_rollup() { diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index d93576f0a..74655abb3 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -4,6 +4,7 @@ use crate::{ l1_base_fee::BaseFeeUpdater, read_parse_env, }; +use remote_signer_client::SignerClient; use ethers::{ prelude::*, providers::{Http, Provider}, @@ -11,7 +12,6 @@ use ethers::{ types::Address, }; use eyre::anyhow; -use remote_signer_client::SignerClient; use std::{env::var, error::Error, str::FromStr, sync::Arc, time::Duration}; use tokio::time::sleep; @@ -24,37 +24,6 @@ use crate::{metrics::*, read_env_var}; const DEFAULT_PRIVATE_KEY: &str = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; -#[derive(Clone, Copy)] -enum ScalarUpdateStage { - Startup, - Periodic, -} - -#[derive(Debug, Eq, PartialEq)] -enum ScalarUpdateOutcome { - Applied, - SkippedAfterError, -} - -fn handle_scalar_update_result( - stage: ScalarUpdateStage, - result: Result<(), E>, -) -> ScalarUpdateOutcome { - match stage { - ScalarUpdateStage::Startup => { - result.expect("overhead_update err"); - ScalarUpdateOutcome::Applied - } - ScalarUpdateStage::Periodic => match result { - Ok(()) => ScalarUpdateOutcome::Applied, - Err(e) => { - log::error!("overhead_updater err: {:?}", e); - ScalarUpdateOutcome::SkippedAfterError - } - }, - } -} - struct Config { l1_rpc: String, l2_rpc: String, @@ -166,7 +135,7 @@ async fn start_updater( mut scalar_updater: ScalarUpdater, ) { base_fee_updater.update().await.expect("base_fee_update err"); - handle_scalar_update_result(ScalarUpdateStage::Startup, scalar_updater.update().await); + scalar_updater.update().await.expect("overhead_update err"); tokio::spawn(async move { let mut update_times = 0; @@ -185,7 +154,10 @@ async fn start_updater( } // Waiting for confirmation of the previous transaction. sleep(Duration::from_millis(6000)).await; - handle_scalar_update_result(ScalarUpdateStage::Periodic, scalar_updater.update().await); + let _ = scalar_updater + .update() + .await + .map_err(|e| log::error!("overhead_updater err: {:?}", e)); update_times = 0 } }); @@ -305,28 +277,6 @@ async fn handle_metrics() -> String { #[cfg(test)] mod tests { use super::*; - use std::panic::catch_unwind; - - fn unknown_selector_error() -> eyre::Error { - crate::abi::decode_commit_batch_last_block_number(&[0xde, 0xad, 0xbe, 0xef]).unwrap_err() - } - - #[test] - fn startup_scalar_update_panics_on_unknown_selector_error() { - let panic = catch_unwind(|| { - handle_scalar_update_result(ScalarUpdateStage::Startup, Err(unknown_selector_error())) - }); - - assert!(panic.is_err()); - } - - #[test] - fn periodic_scalar_update_skips_unknown_selector_error() { - let outcome = - handle_scalar_update_result(ScalarUpdateStage::Periodic, Err(unknown_selector_error())); - - assert_eq!(outcome, ScalarUpdateOutcome::SkippedAfterError); - } #[tokio::test(flavor = "multi_thread", worker_threads = 4)] #[ignore] diff --git a/prover/README.md b/prover/README.md index d29b0950b..8c463ea25 100644 --- a/prover/README.md +++ b/prover/README.md @@ -58,7 +58,8 @@ cargo run --release --features local --package morph-prove --bin prove -- --blo cargo run --release --package morph-prove --bin prove -- --start-block 0x35 --end-block 0x37 --rpc http://127.0.0.1:8545 --use-rpc-db --prove ``` -Set `SAVE_FIXTURE=true` when a Solidity proof fixture is required. Set `PROVER_PROOF_DIR` to the consumer root; for example, `PROVER_PROOF_DIR="$PWD/bin/shadow-prove"` writes the shadow verifier fixture to `bin/shadow-prove/contracts/src/fixtures/plonk-fixture.json`. +This command also generates a fixture that can be used to test the verification of SP1 zkVM proofs +inside Solidity. ### Retrieve the Verification Key @@ -69,4 +70,4 @@ cargo run --release --bin vkey ``` The programVKey generated above must be identical to the configuration in the L1 Verifier contract `morph-repo/contracts/src/deploy-config`. -This key serves as a cryptographic commitment to the L2 State Transition Function (STF) logic, ensuring that the off-chain computation has not been tampered with. +This key serves as a cryptographic commitment to the L2 State Transition Function (STF) logic, ensuring that the off-chain computation has not been tampered with. \ No newline at end of file diff --git a/prover/bin/challenge/src/abi/Rollup.json b/prover/bin/challenge/src/abi/Rollup.json index 24828973e..28f7a5c6d 100644 --- a/prover/bin/challenge/src/abi/Rollup.json +++ b/prover/bin/challenge/src/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -325,25 +306,6 @@ "name": "UpdateProofWindow", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +364,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +441,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,121 +637,33 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ + }, { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "signature", "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" } ], - "name": "commitState", + "name": "commitBatch", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -924,7 +779,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -971,32 +826,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +864,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1126,24 +968,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "proveRemaining", @@ -1226,19 +1050,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1252,19 +1063,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1317,19 +1115,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/prover/bin/challenge/src/abi/Submitter.json b/prover/bin/challenge/src/abi/Submitter.json deleted file mode 100644 index e487193df..000000000 --- a/prover/bin/challenge/src/abi/Submitter.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "submitter", - "type": "address" - } - ], - "name": "isActive", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/prover/bin/challenge/src/abi/mod.rs b/prover/bin/challenge/src/abi/mod.rs index 2c860562a..5e88bf9fa 100644 --- a/prover/bin/challenge/src/abi/mod.rs +++ b/prover/bin/challenge/src/abi/mod.rs @@ -3,100 +3,7 @@ //! Contract ABIs are refactored into their own module to gracefully deal with allowing missing docs on the abigen macro. #![allow(missing_docs)] -use ethers::{abi::AbiDecode, contract::EthCall, types::Bytes}; -use eyre::{eyre, Result}; - pub mod rollup_abi { use ethers::prelude::abigen; abigen!(Rollup, "src/abi/Rollup.json"); } - -pub mod submitter_abi { - use ethers::prelude::abigen; - abigen!(Submitter, "src/abi/Submitter.json"); -} - -pub mod pre_submitter_rollup_abi { - use ethers::prelude::abigen; - abigen!(PreSubmitterRollup, "src/abi/pre_submitter/Rollup.json"); -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CommitBatchInput { - pub version: u8, - pub parent_batch_header: Bytes, - pub last_block_number: u64, - pub num_l1_messages: u16, - pub prev_state_root: [u8; 32], - pub post_state_root: [u8; 32], - pub withdrawal_root: [u8; 32], -} - -macro_rules! commit_batch_input { - ($input:expr) => {{ - let input = $input; - CommitBatchInput { - version: input.version, - parent_batch_header: input.parent_batch_header, - last_block_number: input.last_block_number, - num_l1_messages: input.num_l1_messages, - prev_state_root: input.prev_state_root, - post_state_root: input.post_state_root, - withdrawal_root: input.withdrawal_root, - } - }}; -} - -/// Decode only the pre- or post-upgrade commitBatch method supported by challenge. -pub fn decode_commit_batch(data: &[u8]) -> Result { - use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; - use rollup_abi::CommitBatchCall; - - let selector = data.get(..4).ok_or_else(|| eyre!("rollup calldata is shorter than a selector"))?; - if selector == CommitBatchCall::selector() { - let call = CommitBatchCall::decode(data)?; - return Ok(commit_batch_input!(call.batch_data_input)); - } - if selector == PreSubmitterCommitBatchCall::selector() { - let call = PreSubmitterCommitBatchCall::decode(data)?; - return Ok(commit_batch_input!(call.batch_data_input)); - } - - Err(eyre!("unsupported rollup calldata selector")) -} - -#[cfg(test)] -mod tests { - use super::*; - use pre_submitter_rollup_abi::CommitBatchCall as PreSubmitterCommitBatchCall; - use rollup_abi::CommitBatchCall; - - const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; - const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; - - fn calldata(value: &str) -> Vec { - ethers::utils::hex::decode(value.trim_start_matches("0x")).unwrap() - } - - #[test] - fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { - let pre = decode_commit_batch(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(); - let post = decode_commit_batch(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(); - - assert_eq!(pre, post); - assert_eq!(post.version, 2); - assert_eq!(post.last_block_number, 12_345); - assert_eq!(post.parent_batch_header.as_ref(), [1, 2, 3]); - assert_eq!(CommitBatchCall::selector(), [0x41, 0xf7, 0x56, 0xda]); - assert_eq!(PreSubmitterCommitBatchCall::selector(), [0x42, 0x88, 0x68, 0xb5]); - } - - #[test] - fn rejects_non_commit_batch_calldata() { - assert!(decode_commit_batch(&[]).is_err()); - assert!(decode_commit_batch(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - assert!(decode_commit_batch(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); - assert!(decode_commit_batch(&[0x15, 0x44, 0xba, 0x3a]).is_err()); - assert!(decode_commit_batch(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); - } -} diff --git a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json b/prover/bin/challenge/src/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/prover/bin/challenge/src/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/prover/bin/challenge/src/bin/auto_challenge.rs b/prover/bin/challenge/src/bin/auto_challenge.rs index 6d7930ffe..5c100b9f4 100644 --- a/prover/bin/challenge/src/bin/auto_challenge.rs +++ b/prover/bin/challenge/src/bin/auto_challenge.rs @@ -121,8 +121,9 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi return Ok(()); } - let batch_index = match candidate_batch_index_from_events(&mut logs) { - Some(batch_index) => batch_index, + logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); + let batch_index = match logs.get(logs.len() - 2) { + Some(log) => log.topics[1].to_low_u64_be(), None => { log::error!("find commit_batch log error"); return Ok(()); @@ -201,13 +202,6 @@ async fn auto_challenge(l1_provider: &Provider, l1_rollup: &RollupType, mi Ok(()) } -/// Select the penultimate committed batch using event metadata only. Deliberately accepting -/// `Log` values rather than transactions keeps auto-challenge independent of commit calldata. -fn candidate_batch_index_from_events(logs: &mut [Log]) -> Option { - logs.sort_by(|a, b| a.block_number.unwrap().cmp(&b.block_number.unwrap())); - logs.get(logs.len() - 2).map(|log| log.topics[1].to_low_u64_be()) -} - async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Provider) -> Option { let start = if latest > U64::from(7200) { // Depends on proof window @@ -256,34 +250,3 @@ async fn detecte_challenge(latest: U64, l1_rollup: &RollupType, l1_provider: &Pr async fn verify_state_transition() { // Do nothing } - -#[cfg(test)] -mod tests { - use super::*; - - fn commit_batch_event(block_number: u64, batch_index: u64) -> Log { - Log { - block_number: Some(block_number.into()), - topics: vec![H256::zero(), H256::from_low_u64_be(batch_index)], - ..Default::default() - } - } - - #[test] - fn selects_candidate_from_event_metadata_without_a_transaction_hash() { - let mut logs = vec![commit_batch_event(12, 42), commit_batch_event(10, 40), commit_batch_event(11, 41)]; - assert!(logs.iter().all(|log| log.transaction_hash.is_none())); - - assert_eq!(candidate_batch_index_from_events(&mut logs), Some(41)); - } - - #[test] - fn source_has_no_commit_transaction_lookup_or_calldata_decoder() { - let source = include_str!("auto_challenge.rs"); - let transaction_lookup = ["get_", "transaction"].concat(); - let commit_decoder = ["decode_", "commit_batch"].concat(); - - assert!(!source.contains(&transaction_lookup)); - assert!(!source.contains(&commit_decoder)); - } -} diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 54b709854..36eac035f 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -1,13 +1,13 @@ -use crate::abi::{decode_commit_batch, rollup_abi::Rollup, submitter_abi::Submitter}; +use crate::abi::rollup_abi::{CommitBatchCall, Rollup}; use crate::external_sign::ExternalSign; use crate::metrics::METRICS; use crate::util::read_env_var; use crate::util::{self, read_parse_env}; -use ethers::prelude::*; use ethers::providers::{Http, Provider}; use ethers::signers::Wallet; use ethers::types::Address; use ethers::types::Bytes; +use ethers::{abi::AbiDecode, prelude::*}; use eyre::anyhow; use serde::{Deserialize, Serialize}; use std::env::var; @@ -51,11 +51,10 @@ pub struct ChallengeHandler { l1_provider: Provider, l2_rpc: String, ext_signer: Option, - signer_address: Address, } impl ChallengeHandler { - pub async fn prepare() -> eyre::Result { + pub async fn prepare() -> Self { // Prepare parameter. let l1_rpc = var("HANDLER_L1_RPC").expect("Cannot detect L1_RPC env var"); let l2_rpc = var("HANDLER_L2_RPC").expect("Cannot detect L2_RPC env var"); @@ -74,37 +73,32 @@ impl ChallengeHandler { .unwrap() .with_chain_id(l1_provider.get_chainid().await.unwrap().as_u64()), )); - let local_signer_address = l1_signer.address(); let l1_rollup: RollupType = Rollup::new(Address::from_str(l1_rollup_address.as_str()).unwrap(), l1_signer); let use_ext_sign: bool = read_env_var("HANDLER_EXTERNAL_SIGN", false); - let (ext_signer, signer_address) = if use_ext_sign { + let ext_signer = if use_ext_sign { log::info!("Challenge handler will use external signer"); let handler_appid: String = read_parse_env("HANDLER_EXTERNAL_SIGN_APPID"); let privkey_pem: String = read_parse_env("HANDLER_EXTERNAL_SIGN_RSA_PRIV"); let sign_address: String = read_parse_env("HANDLER_EXTERNAL_SIGN_ADDRESS"); - let signer_address = Address::from_str(&sign_address).map_err(|e| anyhow!("invalid HANDLER_EXTERNAL_SIGN_ADDRESS: {}", e))?; let sign_chain: String = read_parse_env("HANDLER_EXTERNAL_SIGN_CHAIN"); let sign_url: String = read_parse_env("HANDLER_EXTERNAL_SIGN_URL"); let signer: ExternalSign = ExternalSign::new(&handler_appid, &privkey_pem, &sign_address, &sign_chain, &sign_url) .map_err(|e| anyhow!(format!("Prepare ExternalSign err: {:?}", e))) .unwrap(); - (Some(signer), signer_address) + Some(signer) } else { log::info!("Challenge handler will use local signer"); - (None, local_signer_address) + None }; - let handler = Self { + Self { l1_rollup, l1_provider, l2_rpc, ext_signer, - signer_address, - }; - handler.ensure_signer_is_active().await?; - Ok(handler) + } } pub async fn handle_challenge(&self) -> Result<(), Box> { @@ -125,8 +119,13 @@ impl ChallengeHandler { }; log::info!("Current L1 block number: {:#?}", latest); + let wallet = if let Some(signer) = &self.ext_signer { + Address::from_str(&signer.address).unwrap_or_default() + } else { + self.l1_rollup.client().address() + }; // Record wallet balance. - let balance = match l1_provider.get_balance(self.signer_address, None).await { + let balance = match l1_provider.get_balance(wallet, None).await { Ok(b) => b, Err(e) => { log::error!("handler_wallet.get_balance error: {:#?}", e); @@ -244,29 +243,12 @@ impl ChallengeHandler { async fn prove_state(&self, batch_index: u64, batch_header: Bytes, batch_proof: ProveResult, l1_rollup: &RollupType) -> bool { for _ in 0..MAX_RETRY_TIMES { sleep(Duration::from_secs(12)).await; - if let Err(e) = self.ensure_signer_is_active().await { - METRICS.verify_result.set(2); - log::error!( - "refusing to prove state because signer is not an active submitter, batch_index: {:?}, err_msg: {:#?}", - batch_index, - e - ); - return false; - } log::info!("starting prove state onchain, batch index = {:#?}", batch_index); let proof = Bytes::from(batch_proof.proof_data.clone()); let client: Arc, LocalWallet>> = self.l1_rollup.client(); let calldata = l1_rollup.prove_state(batch_header.clone(), proof).calldata(); - let result = send_transaction( - self.l1_rollup.address(), - calldata, - &client, - &self.ext_signer, - self.signer_address, - &self.l1_provider, - ) - .await; + let result = send_transaction(self.l1_rollup.address(), calldata, &client, &self.ext_signer, &self.l1_provider).await; if let Ok(tx_hash) = result { METRICS.verify_result.set(1); log::info!("prove_state success, batch_index: {:?}, tx_hash: {:#?}", batch_index, tx_hash); @@ -281,28 +263,6 @@ impl ChallengeHandler { } false } - - async fn ensure_signer_is_active(&self) -> eyre::Result<()> { - ensure_submitter_active(&self.l1_rollup, self.signer_address).await - } -} - -async fn ensure_submitter_active(l1_rollup: &Rollup, signer_address: Address) -> eyre::Result<()> { - let submitter_address = l1_rollup - .submitter_contract() - .call() - .await - .map_err(|e| anyhow!("query Rollup.submitterContract failed: {}", e))?; - let submitter = Submitter::new(submitter_address, l1_rollup.client()); - let is_active = submitter - .is_active(signer_address) - .call() - .await - .map_err(|e| anyhow!("query Submitter.isActive failed for {:?}: {}", signer_address, e))?; - if !is_active { - return Err(anyhow!("signer {:?} is not an active submitter", signer_address)); - } - Ok(()) } /** @@ -435,7 +395,7 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide return None; } }; - if should_read_commit_calldata(batch_in_challenge, is_batch_finalized) { + if batch_in_challenge && !is_batch_finalized { return Some(batch_index); } log::debug!("batch status not in challenge or already finalized, batch index = {:#?}", batch_index); @@ -444,13 +404,6 @@ async fn detecte_challenge_event(latest: U64, l1_rollup: &RollupType, l1_provide None } -/// Commit calldata is only needed after the on-chain status checks identify a live challenge. -/// In particular, batches finalized before the strict upgrade cutover must not reach the -/// transaction lookup and calldata decoder in `handle_with_prover`. -fn should_read_commit_calldata(batch_in_challenge: bool, is_batch_finalized: bool) -> bool { - batch_in_challenge && !is_batch_finalized -} - #[derive(Default, Clone)] struct BatchInfo { version: u8, @@ -496,21 +449,21 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let input = if let Ok(input) = decode_commit_batch(&data) { - input + let param = if let Ok(_param) = CommitBatchCall::decode(&data) { + _param } else { log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); return None; }; - let version = input.version; - let prev_state_root = input.prev_state_root; - let post_state_root = input.post_state_root; - let withdrawal_root = input.withdrawal_root; - let last_block_number = input.last_block_number; - let num_l1_messages = input.num_l1_messages; + let version: u8 = param.batch_data_input.version; + let prev_state_root: [u8; 32] = param.batch_data_input.prev_state_root; + let post_state_root: [u8; 32] = param.batch_data_input.post_state_root; + let withdrawal_root: [u8; 32] = param.batch_data_input.withdrawal_root; + let last_block_number: u64 = param.batch_data_input.last_block_number; + let num_l1_messages = param.batch_data_input.num_l1_messages; log::info!("======> batch inspect: decode tx.input, version = {:#?}", version); - log::info!("======> batch inspect: decode tx.input, input = {:#?}", input); + log::info!("======> batch inspect: decode tx.input, param = {:#?}", param); let mut batch_info = BatchInfo { version, @@ -524,7 +477,7 @@ async fn batch_inspect(l1_rollup: &RollupType, l1_provider: &Provider, bat }; // prev_batch_header - let prev_batch_header = input.parent_batch_header; + let prev_batch_header: Bytes = param.batch_data_input.parent_batch_header; let prev_total_l1_message = prev_batch_header.get(17..25).unwrap_or_default(); let post_total_l1_message = u64::from_be_bytes(prev_total_l1_message.try_into().unwrap()) + batch_info.l1_message_popped; batch_info.total_l1_message_popped = post_total_l1_message; @@ -569,13 +522,16 @@ async fn send_transaction( calldata: Option, local_signer: &Arc, LocalWallet>>, ext_signer: &Option, - signer_address: Address, l2_provider: &Provider, ) -> Result> { let req = Eip1559TransactionRequest::new().data(calldata.unwrap_or_default()); let mut tx = TypedTransaction::Eip1559(req); tx.set_to(contract); - tx.set_from(signer_address); + if let Some(signer) = ext_signer { + tx.set_from(Address::from_str(&signer.address).unwrap_or_default()); + } else { + tx.set_from(local_signer.address()); + } local_signer.fill_transaction(&mut tx, None).await.map_err(|e| { let msg = contract_error(ContractError::, LocalWallet>>::from_middleware_error(e)); anyhow!("prove_state fill_transaction error: {:#?}", msg) @@ -624,93 +580,4 @@ pub fn contract_error(e: ContractError) -> String { format!("error: {:?}", e) }; error_msg -} - -#[cfg(test)] -mod tests { - use super::*; - use ethers::abi::{encode, Token}; - use ethers::providers::MockProvider; - - fn mock_rollup() -> (Rollup>, MockProvider, Address, Address) { - let (provider, mock) = Provider::mocked(); - let rollup_address = Address::from_low_u64_be(1); - let submitter_address = Address::from_low_u64_be(2); - (Rollup::new(rollup_address, Arc::new(provider)), mock, rollup_address, submitter_address) - } - - fn push_call_result(mock: &MockProvider, token: Token) { - mock.push::(Bytes::from(encode(&[token]))).unwrap(); - } - - #[test] - fn strict_upgrade_state_closes_calldata_gate_for_finalized_legacy_batches() { - // initialize4 requires no live challenge and all committed batches to be finalized. - assert!(!should_read_commit_calldata(false, true)); - // Even a stale challenge event cannot make a finalized batch reach calldata lookup. - assert!(!should_read_commit_calldata(true, true)); - assert!(!should_read_commit_calldata(false, false)); - assert!(should_read_commit_calldata(true, false)); - } - - #[tokio::test] - async fn accepts_active_signer() { - let (rollup, mock, _, submitter_address) = mock_rollup(); - let signer_address = Address::from_low_u64_be(3); - - // Mock responses are consumed last-in, first-out. - push_call_result(&mock, Token::Bool(true)); - push_call_result(&mock, Token::Address(submitter_address)); - - ensure_submitter_active(&rollup, signer_address).await.unwrap(); - - mock.assert_request( - "eth_call", - [ - serde_json::to_value(rollup.submitter_contract().tx).unwrap(), - serde_json::to_value(BlockNumber::Latest).unwrap(), - ], - ) - .unwrap(); - let submitter = Submitter::new(submitter_address, rollup.client()); - mock.assert_request( - "eth_call", - [ - serde_json::to_value(submitter.is_active(signer_address).tx).unwrap(), - serde_json::to_value(BlockNumber::Latest).unwrap(), - ], - ) - .unwrap(); - } - - #[tokio::test] - async fn rejects_inactive_signer() { - let (rollup, mock, _, submitter_address) = mock_rollup(); - let signer_address = Address::from_low_u64_be(3); - push_call_result(&mock, Token::Bool(false)); - push_call_result(&mock, Token::Address(submitter_address)); - - let error = ensure_submitter_active(&rollup, signer_address).await.unwrap_err(); - - assert!(error.to_string().contains("is not an active submitter")); - } - - #[tokio::test] - async fn fails_closed_when_rollup_submitter_query_fails() { - let (rollup, _, _, _) = mock_rollup(); - - let error = ensure_submitter_active(&rollup, Address::from_low_u64_be(3)).await.unwrap_err(); - - assert!(error.to_string().contains("query Rollup.submitterContract failed")); - } - - #[tokio::test] - async fn fails_closed_when_submitter_activity_query_fails() { - let (rollup, mock, _, submitter_address) = mock_rollup(); - push_call_result(&mock, Token::Address(submitter_address)); - - let error = ensure_submitter_active(&rollup, Address::from_low_u64_be(3)).await.unwrap_err(); - - assert!(error.to_string().contains("query Submitter.isActive failed")); - } -} +} \ No newline at end of file diff --git a/prover/bin/challenge/src/main.rs b/prover/bin/challenge/src/main.rs index 0473cdde6..f134ac403 100644 --- a/prover/bin/challenge/src/main.rs +++ b/prover/bin/challenge/src/main.rs @@ -23,13 +23,7 @@ async fn main() { metric_mng().await; // Start challenge handler. - let challenge_handler = match handler::ChallengeHandler::prepare().await { - Ok(handler) => handler, - Err(e) => { - log::error!("challenge handler preparation failed: {:#?}", e); - return; - } - }; + let challenge_handler = handler::ChallengeHandler::prepare().await; match challenge_handler.handle_challenge().await { Ok(()) => (), Err(e) => { diff --git a/prover/bin/client/elf/verifier-client b/prover/bin/client/elf/verifier-client index 3c991ba83a6c467e8453a070441c3f0c0bcf2e07..0e0a8f4347b7e77de069dea1d32a3154e20b90f4 100755 GIT binary patch delta 1977121 zcmc#+0bEo?{(lcvT@-au)KyUzL_k4Z6%`eAEmTab)le}hK^KEWSP_fTS}H0ks?{MM z8Ff_DQBhHHNgd@@R8&-J(M3f?9TitrTX7dxbp2=E?>Ec5r<{7%{d*tryWijMH^1M^ zyqS6P=FQvnDfb6@yQ>4;V?#cVDw617WB<{^J%9hSd{^jXl@uXLCY4Gug#q-B%Znl> ztBEzC{!p3CN~Fn{#qEe{`fuy*5wW7R+18SqPC&&*4nCmy-Rs93kY@%OLqjwRUv&Bk)? z8%00*K7EB)1A7v}H`$UFRSg_no-zKF>VG`^!ohp5Kl1UIQrYv&N9iv|Kk-RGcwP2C z|9Q>6zb4$u{zc`(ZK96J!XtNA>?b@5?E~|g&_^SJ!d}8q8)xZAw#f^r^FW>a_@)@ol)5i=V z&Ve3c8)UW=Kk)d?>2LjOqwnf(^6PGYXyu(1=U;T&WAC^(y!iSP&9)c9NZO#fnBBpj zwM2T#9l2{#eo4Y}pBM;sp!tI=cHupW-AqQb0# zJWB*I2gR7HzUo|bN$n%oH(ayzFSThS%HEB9`txV6di!yb9aLlq-tT;dJf66Beej-- zmfZD$9QgX&4-QOwKlQwVB}YP2H)IoEkeQeUJ57n7PkLxrYqweC1ka@Ek{GVdmD% z-C4bxs+L`R=$?XttX+F@3bGtuT(o!C+0VrX)kRew7`?Ur4w4*Pkzj#SFMWI7)hnJT z{_xN14B^t&JKy=`+`EkdckI4s$6;BS#Dc10xTNs59;wc7=TJi|;;88b-KdzR1}B?&k{~>1VI`Q2Oq@ z`i=KCetOZjcbmOio%yp;b9QF6{pFhv+o#5lAkL8%!T?i~e{!&7h~?bE@|nz#5Ash^o+B_tjpS+Rd8vR$O%dDp4s%0r+n2^w-)xhlF17PH=3Z1*JfY)dVhb}H zeYgC*{JiCN8V{$1-6Ol^!N65M|F=c&Y5H^Z7dR#1%raDWhV~fOC7BmspcR0jD}P&T zSoQDxxg_aS0kf0;or4q8x1EVSjqlGuGUhaFKLo5i09cRQfIJ&{7xH)lc6Q`N$djH2 zdEEYr5+R{Hi2O!^7@I9>eVsH^4p>`$?wng9|dUcb8uSev-`Do`Ezno zN4y5i@nDz!8)Ktu)_>=?clMd3FW1?}ooHYdJ_AbIEE zpCV?-17;TF=NFRarp_a#xbQK?tfI_qg}IkoJOeFTFE7m6E%oV1l7%deyvV>4DBg3z zV+NwZ{#^@*a>*pi#j|DIP-Jz3N0BPIRg#D3zEpQQ`Q>-7Fs;y zv#6PVcf_+JY{Ja!{GC}d_iWvhSGZ>;%}Gvv-tOrId-C$K3TAF0;n6e5vFNGfyy#^- z*?e;S-0|eXnE66M+*1dVX^9g_c}y}lTSSJhnI@Rrdb1_KvV+W;EyNGoH!40iXDiG9 z5PC5!py9I$FzcttRv5|O6+|AIVP%-r z{>25EJIN0>MxC;TfcWvo1dG+u2X0MIVm&4(+E#v~*I3Xip`z++%RU^ptw$Vd`Dy9XTPx7+HlH->S=GL3f z9SHr1R9!flTzS@G-0wW{;?fB6_1Ur9awHv1}N0HP;rtyZ{tUQZnsAbz8dLNNjI76kH zJ~An2_qNR3%mQ{c*Dbe0U>KuWAp9C1FN05reeL077 zcwg!*m_b?@VKK|d!3}SLVE?XU^7`IELkiUEXWvElo7>Ff-1CF=gNoYc0%Yblzz4@!5TScplkOHkq8Y zx$x8(g1YK!UG$vK9vz97VR0lq*=!&ZuS=naZ%a?)QyJE>hR%zWHxT>BG31TwLdbxN zCXwwI)su`Z<9Wf=Gafm7XV%XAg3J5b^4hp_joaxJne|F?#g>I+RK{6&!f4w&=YsKl zWxhFa3?Z3I{SN05*5vQFehNz9gbpQdWv)jLw9VDV2XS|7oEt^{c}wsqYd?~FbJYMLjr@<{Rabe@J!8D?>Tdg4gTjBxcT;k#@QiO7C~9LSkUhF#*n zNJ2kbyoV2~w7$txDJJeClg!w$_Ec?#RYwqM+c9PQwt`GLL!G(PSvYfd!8V3{HNdW& z=Ugz7e6?;c_YPTp_KF$)a|U@HQpRhSrg_~pX;@}KPGPp_idE1&StgllMiE>7&EzcS zSn{`BadHItvK0Fu8UE?~&}vvufKga?YM^e=b?e znnIRbx|YmM3Q;fBqc8g-FVuQ6sWh0pSM&lGzz{iqR=6mD+18AyCkjp2c*Nq)Bevbq z@>+lYiQ1cb>atvwGlZPGY7pj{j+X;=XXk7$BoFLMAoH$_J7p{9^V<>Q^YY=UIHWK; z%d)$WHEsXIHoRc@D7M(O#gVm*nz5?}Ue4hTW`rR(XImC|_sYFc{P2Pc$ltB zlyGu%RuK8&Dq-qB{k&0VA{Vb8uq|_2b{26INBEP?BgQ#q^1+Nya;SLxX%%G@d9rvS zc|2}B$-a8*DO0e4Yyv-F>{7w+8Q5Ufy=)A*`s#MBh7fIeN_w zkkVq1y*o#c2d*s~Vd6`w7WG2QX3|%bB$8K3CX$8M?GVaHudTzJ1$5C-TdP!jviT05 z!Q+_t934`JuNgyrT|UC^Qk4Yd&7K?2Jf4RQYASj5`g>2OK@BEr3i$Wy6yQY%3(z3pKVYdW39Ydn}W>mt=^<)R8jeL^m;F2U^|35L z{)ZJqkg=2Wk!{jYkGzom(>BNu)*xqQI&;L#tAl^=CHd;jCS2_485_2{kPc{lc5D>C z@zyc&YF2TF&$?-d%!@XUlpTolS2MJT$juYU$7Q2WHdB~H{$4h%FRkUu(X?fTN9E)> z_rQ>OifV}@kJ$$eP-~IMw@x`_bB4bB%#B0Bhp0u`vNLn{4vQz)lAXCbTP5PHY65v? z|0q&*>k<;`P9u*;TgaF0DLl7)W;U3-=p1o+jpnSBiI95#t~B!2{z*VsWzIh^lGGiD z0s$MM966Wf>?TXe+98rOIZ{&Bl{S+*NQ~hP`h<(D`8byNNL#@D`^l^2Q3GN|tSFL{ zTLy%WA;GtY1{n`Pf=IIe_WYm{WD#W3?K6WKkVTQHw?_y0kWC<;w5}%cN@S3OK-!5U z=-|wN3PKhhoEP9Fq~PF;0Ao41_u!JCgmN&MPWHb!$p0dw2L(QgpKXu!t?!)S zXT>=~4hoDC7Kaip8hQFfE7l}QGR7{B`tFjk6>(rhB3>sd52htN$2Ej<5B3qOc{WdLo z?xE0tG=*GqC@SC~g*raJ6n7#r7Sdh0PuUi5Bn-S9)vPJJA6oerLuLQ#w z#B!8pAWuM^guF#934L6B7Nko->^U2Fa1x*!?TwheV|gSjx_8qL>@;_wqkU+YmJIUV zRa#8falQUj+==OPlOti#Js1TI7|?wV1hlONY)0-wtVYa6eFdT!vE~9ucYGtDc@v-s zu__IC=Vn}Vm(oGdycy7g4yur+AaB#Mv z!7fDW4#+@tHegc@L)!lu)en-Cf|#2N2BnC0#AI|3gS-`aEjnyQOhrGYo#4lS_K6%( z?qlg$|8GM@%O#M&fsVaS;FdhV!hAqGViU@P3qT%&=-UOn3)43vFGP&PbjcK1e5nfs zb?BfP4cj@Q+>N{lc`gPppuFY^2<$;jMRX!YB6cI1_G14pLqYOha9~3ohrD+;$g2wh z+x7r^FZamyANqG@^+QGB)#Hvc|16f z(l9_fVg=&9CI}e%x)#%46gh4GdV^E(Ty)^(0g!uZ3UY#b>3rcc2*m!B@WF?|gNNI~9# zybI%m{RD9+;`P7BFHkcg7@Qu*^gS4$^GEQPjaY#Ji+=$*$HbqpKXSpDV&Tu=um%H! zB5y|C%>(y>T?^`Kk@vXpLozD#C~-r~x$j@#h-0CSbNT6_s}>y?5t9%j5wm}VfMo$w z)KkGRSkiJXKV3|M^e(9g19T!*AT}ZTFpwFsQpdw&$Vd^QArN@44vTdh^tAu!4g2E_ z=pYo)j%YXRwH^53kO1=7__fJ< zuPnrIu3#a!!t$8EIO+nFkFUOYsDiIq71Ph{cp{mnFupRymdwQ1X~M!+K-da$PTjnq z_#2=)FCaJ8#SBo}g)(DK`1rt~D~d?EC(Kn9Ocx&MQHyQne}x@7|H$b*s7}$`5AQ~K zXC(BV#ArY%3eba?I0bke>eFL@x6cIZm;;zLn;{*8J?aNZYO#VMJswb+2bhcrjPrpv z%>pb$eFmmWLwUkn(3d9znpXq1t^#zP1K7*->>5yn2Ei$yXhws|RN$74faU7}gEs(% zBCkMwVH(KGQ13$?<^Z|rV!*U4z;=r2HK-U3%Fw`&jfUF+n+gD{_W&jr0@fm0b^{N) z6tD*|4DA~(1GyXR)JeYj_-Mh^=lgwjW=vHq6d10evX< zA`;tC3;Fc5$it!aWdX$Vq=i(`zm6wuvopmZCWUTrD%j13Jr+Q6)@g^BtLoGN?G_40 zCr)#tmJetLkn;iUE^20kH9|-xkwP;n#Jl zfOS=8mZ79Gvv)~61HE@cppyFlE!Dp*)}PcL?Z2lRsPg_Z%aHMb)39gbhdu-G80h$) zz=7{cz^0F{vNBCX~0dLq@7T1dK<_MwAd+5q%$;z_0`b!5@)`quV2v zHEKt=WaNAdThqvfx~+B;2eZndM>_IQppp|g9|{X}ZZ1PU811h{9)kQpBbnxj3a+M) z>X>9zK7E8%wj_Ll{3yA?GhfapPk2_!PV$o{&sDB~&DneC_-S# z)dOfkOhs&A`X%)AbfUoVGZch(5G)B3gsN-i;WB*oatyc4a28vxfls5M6bs;DUXq zsL>flB2O9#4!VCEq^rm1C~VAs=eT3knWaw|&FpEH;TbqxY)})@hqdD%pfvu!K=sO_ zbI>sHzi>!9!oCTopB}D!XOKYcXqe$t%&5--0o%g?3nv4bbleyLat9){gDal{4bLjb z%-fc|oWAm#x0~MBC*@q6wY!i;q%Ul%V?XccJx##b+t=*y>Gc0XJ=-k7jzKSK?bkR9 z&!wC5q}Ivgg61V7u0}OqEhv2vrt%byPIS3Z%dcMtkn_u+f}CH!?$PO6=q)(Q#D9pc zQzn$6wE^^;2kz2kg!52L9~K9Gl4k>kO=n13NRm!bHUkWL5UWt{P!mWJci_`;Eq&a{MI(a1Oa}mSPt{#!6@6~ZGKN+e$M6amF0L2R+Bjt#3i0O#! z^Fg1M0N8Ohpf3rq8nFqn7xkv)px>T#8QJ#Qs32!EG~h98jV&N%1iAOMys<}7$eZm; z$On+ekB)J@hKx_k-bK!*WnUrZ&H8JenzdDWe2<(r>t5tMTHq^?C9W?W0UWnh&5?$p z0q=ytx=z}vlCMv(B{1CH1zW;!eM<373lDP9H87Uh&{PPX z!3aG@(^Ac(sF&YEWs&qR?0l^MRKODC2IN-6bi_2BeKpEmwWw%A3|)_o5#u)iPtfre zw4j zf#Y;`aYIm$M$x|;G4lF8GGHGilJZMhL|EVmx>#EKQJAas7RX)3t$;nq%aFGtO1FVt zkMXE?qTcBSJCBZYImZgnyCg2)Xha8`_lI`0E4>{8rXK{XL0*cy6)_!e$FxW<+U+y} zNokGSdejSNoDU+eAm=Tm1vww2-ayW;y>BDu69N60@}8Hx-@1;}yd4*D_b~`H6dTvW z$ocqqqgVV)|dmun5 zW~2=<^Z}5k-4Cd8Hug26z$YrGyjGV`(&@Rw)5SPU@4tbhG1#76=>z)5uIRo>$Qf@x z9825Dw6=*sDT|<~tR-vPwnQ9z2N)lp+mQ1%{oy-o;=8E>#k>I@N6u#u(qF(0@04YfE9c+`;Q*1psY)G-F5N` zsOchCyg$#SPsYj=PXB!UBy0Ugf*MAjjtvV7=-k|AJb)8c4j)601rG5 zO8%qagVkN}>>640qh-Qz5dpef|llQ)vu#-u7;W7@6p`ik_YsqF3@<`_d47j3<@nx`S_U z)il95_+MeW&cBYYmU!SMogwEwl-u8ejMgIdAUfU#x$P}-$wyHmuKxfkgEzrjJ|Opg zv{ZhBeELz;fS;I>WOj@s9p$DF{@DA@t&n6JS@!Y#bNmcz(?*e7V&muY z&#$PA+2qcIboz&hr6|vyNxuB-qVW1zYOIv3i!--fzAo2EW_czVLTO|+p%1Lv6ipuXP7K%-t=zmMd}82& z*dir;r92^U!VGmvt9Xhcf&w;1lh@u^9OR#J9M0*wEzp&ABg9Qbj6eIz2S9!%$l^<WB2~k z&Il|Xo^A%57_bIQ>_BuPwjnklrXZ$cx+LUPi1D|%AgBA#APyD#5KB;=jy#de5hD@n z5mOPph(4@|%77TP1KR@u4T$k3{NP0c`kLCelY%Cm1;dboJoxQO*ROa%;$vC_9aY(& zq?ZR#`6wz^aH~%mJGbT;~U`owy^^_zc>6E`EW3o4j|_ff!=S(;P0c(NiGF9ThVL? zz4FbWpY;X3jLO&~stXI+fcCtgZi!s+{lp0^rJzI2vJ#&+alop?5LO?|9 z;W^z?0s@QEihgt!)QE8-r+ zYZ324Y(RV&@h!xU5RW7N6VdPk#2X1XONv0jEW{;<>k)S$mLe+um?gV|{Ihdq|7>|_ zxS!(5zn;$X*(B62|L<-mlwEV=`9jRcDLo@1k;cv$!xFD)&OPA4ySD4ayyJVQFv`;?SC-u&rz*}>5eB91>i=vma zk$B2U1to{THayv|b&ed>_i4$Wx`MYP#HC!JeZ7X7EWd7-gSbOrdW28RLN8}?IiM5 zR2F*@Ih&K5%${{oW{;(qEoD%`j(g}IJ6(J5aS!jytZ}i`6Mub>zx75N$`?+B`9b!= zsp@G7SP*+;bDlgPz*TiAR5Zu1%YfSueW))l19{smfN_W!h;^v%MsB(l?A*xfk$0k< z9k@$MybTO9+<;!>#}SJWD^c%3G$R`KL%LeD>qL1va?b(uO8~3jzPEyyF0mvKE}B10NqDzAV9wPKMGyuC&`Q^&0#qz~Lee|it^2-bS6jMD$Qw52sP+mjj ztWWsum8X`-`GU7uOXcV+=U%8C3$bjATF$uYEB!U}THGF84m5ObeAK21f2&pu~pC6I>STgjAq9YDPzHOjwCnjL78`$nE`{ zj{{LXtWb;Xujld;Ri(9i7PXTEsXbhXan`_Xshsd|26t9)>_ zyxdTK2VUd4=Eo{uT_i6LOiqYZJ}}b{F>_*-$z$cE%9C5=Vak%1!(+nAu7Z-KL1cgE z;OoFkQX*azYKp*6pT|}lq$PBuW>_f0aawhKjjWS0b&auO!Bl123VHE5QwW?EI;mC< zYcPzl{yMD6^@)gf|?tme7{285Li7cR$0ALo*vjaGgjHVQl4w{&4iPp z?Eh)wNM%u&yfd(f*383U@?3+JR+`dimL~*IN#F!|eP9Vq_Ej=XUoZ>8AC`j@=XrEt^p2^@o#)8Y4W)1*CIn2Hp?r0YyhfRS zj%*3383pAXkL8)d)?SBOCeBbRZe7-;Sp|i=mE!GksCr3~DvP1sEojf{C8+`0f4_R1 zUvN9iXowqG0{$GjL7~wrG+8wk`LuKN0F#UNfdp*ps)QO;phF`%G-8M4qfCt02VlFy z+66@MLk?XHRf-v<_IX)ZjxCvmTXM7LOP7?F;3%o@y(Ks* z>+~-FIFO6OH#bZk2N`L_t85cajrdu&Ay===G;n%9LzlMzhPGB5Hq6wP9nie#U=UwE zRXN`-uL(?gAXd3~n!Gr${svlc(`b*(rXPNuCf{XDcmR9!+OIZ@QQllDj}5e1X}4WV zt>bC`k6kA(Hg?WIqwpWMj#PHU(dQUlH`3XEoV=ZN)gkB0Q;Z#@P~8XRZJ|osbUDsd zhZTMp@kvC}co?3Xw@g!;uI*O9Hsry`tC2fz0=@noyA0*Ih*_8Jw9u}fv;A_l8Vr(q zqDb0qz8H=wG%YnR)V{fnx%SPp5vT9-#VLY@r)g9nFlg>K(#C{Gxzc6Q2u49N8tg-U95EFgB}YSmrm27?#56>649HWb0d^o( zp}sv9j#ap2gB@*>0xl-D30NB_-;q0?jG z5l=2UZb3sIqJ-Fm8Hhw~jmMJC1#Cjzfmn#>MtwbEFk&xaRlExvw4uO`3GE9(ZdwG` zh`bFk7cma?$%x%3cOWlC-mn<_G%o=RMND?#hgLKwI|~dFlK@-K1~ecyB6o5+o^k<9NrqG(GsVEpiz|=}+H)QMp~|bhysMEroQ) z&j;KG7%Y{cpzHitW&9?3@$9>sY{%}&?vX++NNCM}HX?j}nyKEInR zMPH2=qi{X=7zxD^H4-2addhqERze(&*UkGQn?`~3>35Cd=009$pf%)Ae z5A5wHFuxt@PoIdV9qj1ZZV?8q#K4lS_V|4h53DRpmyas0F>=VTQhF_7g@%{!$VHxU zftKi4Wzi^kZlIA~I<{?=*V9Xy^7LkTNg#cKrLgN&Kzf`qK3$Gt^WwmosMsTmE|hPP z4b3ZK;o76Wt(iW)1KXU1#i9qVWBM#hdF>*3;vl@5s2ektC%4G64Ha4RF&E#;9B5ui zrxeS@-tec(4BeYYfi_ZD#fF+p)}l`{g(l>M+(zI}3IJuLQ?V!_yz zlpVZa@y_Xd^-_6ln|$FQ?>aS8>ZLsZ9`{{nNP?{U?>}5U{q)VkaWmD^)So_Hz3$Pk zlHzs?uqh&UU_ZjXDWxN)T~qZ7nU|E5XCs2tt>gA9&-T|o-LMZ;j;$}_89O&(T)_SG4l_p{B^xT)DNFp3-Gv@G z{}Oqp9MCjhd47kyLAQe^knZ47Moy&>b3a?I{5e9Nn8+_PpDkBQU9?O)<~8(R7##CT zo|y-q76s#cNR`l9_33=s&{sN+2x7%tyHmb$+9h)!cs}A4h{cFEA$I&peN^k>PiddE zLAoZymRq1{bl$4P<0$ta8c|={k3E;C-Ufagh{#=%P9SkZj-d)9j7Q8sbRZTYmLNtV za=RqtsfbO8#dk2jbVgNO0RcRSp@@~Lfh2hmQxFplVM)-=fV=}8TT$Lr33iEh0ZNFW zh;2;IW^{HGI1pnH>k*Hmqax&nKY+t##3ICU#011%#F8qoFTEGA_8velMRi7b91UvG zz=xQGn06l|NX3Nl$ZIg23FV$Yf?aV9U>ssHVms<9kvG)fjM9OER>U4Otau04BX2<7g?6dPZI6JR<53rUXhne!u>`T|QP4Lbh9L$&2J$+z>q2=3 z@_lunuR*LuEJJKWY;oa-O2o*=Az}OzfW^q`5p9Ughe01%57>pg2eA#&hJW zkj~YKf;bdZBX=XOLrg*JMr=YmFY+Sf#v_=q2Ea1p9>ios2k2c=F&dhlf&`wY0n-pm z5zA2D&GmllHzAqOr8|`yZU$_tC-N;k+0C(&JEJFJt)E8d~^0<8L z|E5bpka7uN0wzet1k&XoZ$w^N2;4|Zz@{F_XrGGuuq#0B$Oq&ZDn&apqBW2Af6PE7 zCP;Te!h{^a7)+3e0Xi=Oc`w>`?*iU%9iWrtiXQwHtPV%a6ZGo%OAVWGZ0CmA=fLII z{s1^U-VE4|$mJQRw_gu>vl_NqTQc90Y*HR#0`^Epafk9!C^O65ifxaIj_35+rW-D54qaf6E^rsN(mD*xOTO<(NZ+461}`q$u8sw!M+Ln~sy!$bTWKU>JYoZ0Mk{WB z0QwTwV&MMtRt(JTV$OxY9`sxF3XWh-3|NfVfd)0D|2}YkdVSz3UEoHH<9r22Fn!>R z8zFEqRyA*2yd?eU^?}XjX-nMZ4-Ec`UAht*ZURMiKY{zx>jS%WfxGpAk-KjM?a_7C6(U{B`)o!#Qo{@fs1v4~?#aoeKg0#UEyXg@&mdTL2u9!j^c^_lfF1pIfiB32WXD0U7iT#wK9+U(~({2hs?R zC{3QPTw{{A2PV*!&96*!ZKjN^WQNE)*%IeXA@Yg=l{08E^|bdbR-3A!5PY#ZVFOeG zpMq5DYM(E*^fe*A^(oAS_gj3ex(;3WaQ z!Nm<@HbNPS4uPUqcS+`J)jY7fpTK;rx<9=KZ`;srx>SXMYcO!UuEcz;ng#YR{~G)| zpOmU8=AeZyLZjZE92xn}ClhTPY{!#->(gQndg5E3+}sm-2<4tI zmwfA!iOJPw;@^Q}YsVWuz5~g)336q9403DNm6Y#5;#J)5s=RX5IyoXXbpy&* zW)&4mMP=v~T7v%`BC(O~S)fnMBYl|Q-;L4gqhig1|L#$A(~W+iU%7jXe3WE+Oa{xd z{jBl(w=OMr^_MgL;HW=6&AB>V<95v#LIrl=B&ifnC%?Jj&zJbk4OT?oBDRkR`{fo{ zar9+;|C0lC z=aMU98x+aEbBX1W9-e;M3V&SCpS}(6`nX*M`p?D33hml6GSvTEft`}R-YY&#FuD@e zk(pjg@M(g{p*;_w*o*mj;7=3ic~EP;zgtEAkf1+(>L1ng@e(&I#lZe?97|)xK*BiA zo+gY{Zy{<4Y~KjXH*xi+Pkso}aXWJsl)3@0r18255#Q{^M+X{?{IzqGu-hvU z#}&TY%Z(n*=rLC}-tgUCsz-IVmw|2WQWo!u2y@XZBr6c#?q%E#x#Lw+s`JISd-2?L z^;0W+7gvA!o?3`ImmAVub!tYexR`C%RSVzlr3O|9VE=Y6n-{Ose7jc<`f9>CU=(GNen z?Ygtex2iEeUq#Em@VCU{>kHtH+Ehk-U71aM!%TkD<<$71vFmY~tDkN1opJr?gI`kp#Y^1KnFoca#_3wNuI2D8bgY8@ zHyhuw3}v*{vdi;HcD{M={Jntq5+dLE_IU!_y$r)J3K$srA&Kq}4GFHBYvt#V;t@TBFi{a`cfb+h6( zL$tR-8vO>o9+bBs!cI4Tp_Esq)17W7bVLJvFbwb44o!f9!QO}?9lPXf0%kQ{47(!r z!P-#XfcPrb^=9Rtf1t0-`6;UsdhDS$*bx-{a%F9myfmnf-ccp5JR#N3G!;8BeYGRs zBcB)4JqK!ji?Zn+d82FUtw49PK=k+<{bMg#>feE}Q*ZN5BHu*i?2SRa{c0*_D`R>& z`^L9~KKX3_%QW9nq3~rOe)$2KK=Y*{O6I-td5SkdwgvSSjeqZk!QrDzxU=N2zQ&>) zn=j8CdtVNelfQ=e5)G%iWpC8a@|K_cL>)(Y3!=XTDpx1SURO9w?JO288d09a<;YW~ zf?Y!#U?JzzfVW2j#?3&U2$--KumsVEIG}|YD9;=V-{E=%Up3;3HM0iNuYI9qB>0Zg z8v2;*gjOQ5P0zUyTc{hYoHJ0{A<(CTNW#p{HPPbijJn_y21i$M>URQ);# z_{RU-V;Tdg_eHI~{4Fi7d{fH}ty*6A4sd=KoBOWF>2$01We`Ay=r1Ncr*&W{)Ry2( zx#I)yhb5NM-xs)&<&sCb3||N$nvcZyv^=+4%NxJf^3LzHy!;0(kN;H5YkeB-lFI(3 z5lAgxX?d&8L2f(f`AO5)iE})Rmb^~&dM&3XK`Z!w<~06qo&k>uYJk4wtsWii&=-+P zr4fC47GEkJ+9yzr#%X!QuP`6s&8XR+)!TjsJrB@e*6J;xz`4F_ieInBm#Pc3IV{|w z<;{cr2~;1Zfm(-=JGAzmzXA`%h#4J_L0%)iPR=1dee;wHAVn!o%XtFNU$y$SkF-4a zN(jgsrTs&#-WmfL<~7*%9_o4g-?|ZY9ER5kcmb0C1_5~nDt-X&;sRff)*$yOZIxPH z*7D+f7@GLl)`f#D9joEU13k|`+V@yuRNI5q8gZ%LvC3q&AK-dM2XFOAeh~sXkh|a0 za@*(N5Y>_?M;p-F4mH3F*cJ$S&fNyaY5j9S!vL*;G)T)!jaqIWtmU>~Ew>NT@@$iq zSB#*XoqwJI%P6gZcZ`-djMH-O1T8n$YfD^oM9Vv#*7A&J@ug#)frRI^1_>`|x${*m zZ+k<_v)|TobDNesKh$#Dr&D1oJ8Ct4&a&;ko}?y0`kje)f>S1 zJYK>(ey(qQNvltJTgywlTHdHz5pezm^nBKw>T1&pYF-7-OO*YB)?u8kglEdTbSna` z4sl6}V~yZ^WA)(a%9y-O<5-QOqc78Gi~)MlXPxRxL9 z)N=dB!1*cE*HG_7@!pa4KfS^KD`)-x|1}_u=Nthwz;4ad@yFhw?IsD4eFoG(|5hmpd8+EEqe2qx}XdZ!6MfFeOXN%Z6y}bB$Vm zo%ve(>Mr1+P=2~W`BUxPX~kz+UZYzdsC!4NPxCJ*sQHyDKi2B2To8~q%22+30OhB@ zP!|h1=2dw7eXWDvx{dVWeS?eNpL@TCfII_9|Il*tPged6&2WoFDnsn;}xj|Ze@(>*#s^#g!DQD-OXP`JlYtTMY%Zo;9dD2)N57Tnz zBrR|LllI;)?kU~cw0-GV@p zZav_*j+g7!0}^%X0i8NtrduDV*R2n@ywTb!vBzn-*Q(|AxmxaBpyl=@TJAkd%k3*Q z+$DKeYXp+ruI1iTEw^vda_@y&Zr`fq-tAg$pDc3P|FUn^j$AgP<;{0#d1H;1dk<^* z84cB}|DREU-`JkT|2;FH#{V5N0P%mn3}F1$>%_(cb~K)=<((I6d7*B7z_3EA&%Q{@PcqPH@BdF?pzg7O?9dD?I;BI6eV1;1 zAXInvoPAvY{GJH0c}yWS^I^ugK5uLOo;*jEgV1})FpRC=WROoM&g0qlEDx+xx4)_1 zUp0t+e-*P=s;uU*eP8UW-%z6a5gGr!krRGH24mANXH~zdKQ$gUI_yCCA1F?ue|q@^ zRK_+&pgdmU309*b=3BUA={NZ#p*-^28Oo5ml3MkE ze4DFd2z>vD0Wl5Hi5QPqj#!Jh53vm~1+fJ&2GNFCg&2nD0F01KC@4j2K=kiv#V?EFw_*F3UfH!eXQX1C zDw{@RnBmJhGD4sNN<)-GHS)LDy!mPz(K^V2GDgLc|@(D;ytBCkbW zIbNCekUY=TjKwoU9RGVIxn@Y8fM^W|UW~kLEbuPmji^sXOpOA4?IbN0O$MGgK}Gu2 z+VDZ@MTG}B$NuE*NN|)oQH%Y_+b}~`3)lnFQU2r#`m}2b7#gtz9Q%`7Bf!2JYno#d z%1gsQ&oN~h z$a9ewBdP)SJCHYV zdl!D_MvOX3Erh+2ty|2ujg#A)pa?7-A>N6OpGP zMj{p?_M%-O@;2l?#AKAWAU6SzkUS``qCp0tZsUCOR>+@tRaZC8+a3)H*gjL;H-Dt< zPjW_3-_Iv1%Z|#?hN7~W@PpPFj|2tYjGrxaL4jOe7hyCMb7K0lMlrxm74W0i@`xLz zd1U$*K>q^ipMm}jpnn7D-yr&Dq<=y5Z!rBEa%7q(_#c+>`!2(3Wu2NHd`3lolvP>u zN$~Vlx8S?y{HxX3mUK1|O1uFQ>L=T2C{IA-ztXC1<5z4W%x03|F&pZrn!P76MJfe9 zOu#Z=`8Zg`FqEe-R37;;c#g}6st`mA{tC3s1Q)f@C~wE#rfPG8%ijoHlHO79er*6f z=l0#YjBswj^mVs`pWcK24(Yi2?+s4WCn*2U;feNo|Mg;eHty>U^xRzWp9L(&bV+}J z^i3y0^}2I11#32^l4sxBzvI(MZ@vewJEsc7^`-axX90UKUHh|;-uMz=X%k*|l3xTt z&GV>u8F@1z>YHByp8WzM@?=bBM0ql%i}!$CR}*0CQNU)*fYF5xl3oKv3rXQF$U9T^AaO3$Bem>z6A#fKEOugy@l>uG@z6_`VPv&ojYX9&3FC7+bJ+ln8_u0d|^K?s;v<(8K7XViM*XYtZlAKz8 zrU7ib&MbY~qW>^pDlIvGg|KfPLnk#bcTs=E#r7VwW95?qVn!U9_Eqpp za)f0MWK=)XNJM$q9%aPW!83yFUqbQ-vj5FVhH5^OVza0IN%~Df=KM1;Uxa3oWk?mR z9Gp1mRE&RSQ3^$}Pav-JakJGCDHdPZ#9wTcs_4>F1npLO`9UgYQ{&RTP;~D;K;M;s z&4?K&??J4%3iJ|hD}XMk2nA*|tU?Dh+%X1)bk3Fuo8bFTxQgxI1wq>I3qJ{{9lqr4jB9J`qxHgbfa1Fkp~wxWH) z4UmCm#NtxmHHbdMV$_?ETWSm1YCv<~# z`jOu#)4mIyH=-2f^aVrpxb>SO1>Xh#Meh5p&;Rb{M#HbHEJ5w9kOoAxel1sL%ew3SVWR zSlc9$DF+&n#~F$GTbRwZ+| z`LZ~V1Si$ZP7pn~z0(BpxZ!{?zs`b7TNS;@A3lq`_RivIKM)-LG5e_Qt77l@We zweI_^R=xd8RL_2LR_mW$4QJzEZP^AH_+MeF&cDjp)mR@eQD?|`Hp=UFK}MSqD-o*^ z&4{)FuyY{RqPzlmI^`_Bl#7BMC)NNOCZjyJ2;@zOKD28?l3sn^(I0l$|Ad45Cey z{Zgxbr$QOssla}7)%iLU$MVK+f-Z?WNr)IEt|QNHsT(sXGr+BRZh!_|l1^~OJow~}Pty! zIvd6T%Pq<1+)q*<4Rp#8AV_`qNYAMHa4(_+SGn{H zbyX-Y9;bX6Zk`zA!3}@wm5>PYn4rD~sk0)?(V>%JQVf6;Y($h3~5dG{wD=42vCv_*2&*(?a?pK(74*e3{g1k)S zwrF#Bkbg#~JQYpbP0=1GqNd%jUvPD-qLo8``^)elHBi2ODLgE215}qG<_rAL{SkhU zK86niJ5+b@`>j-_e#NW&vGQf4c~Zc~vz0%eEl&*CJ6ru3yuiJXCZvmgP)q2a^4>Gm zd|Oc8#dX0n^GYG#H%>FV4D|c)=od$3$P;W+VAJBNDbTdHVP(BZ3(xlJ>gC6%+#<@A zoLF=8pfYIb%2N6RXffF8^+~UxNvCO&z87m=YA~~|Myo8K<5Fc|oOy;zpRTT-tkhFE zYbJVoCTHJ+rk6KRx#c8s50y{plLtuKl)uH9qazC6#dCWcs;KizKsU;r?<%vWo999A z<$W(CRbQdX9n;O{1$Zt~zMO833i4-489Rga+iG5T=cUTl8RmHby_YJ7C{DFg1C9&0t97c_bFb0zbu6`zW$OS1)I~YC}Z1k~7CVf0{RTj#`mj zh@9)OD^_`R4!usSUI}${p7Pxs^Q53(@C)?TDr4i#&OsktyLj#LzXU1ncyp$o^oS&5 zuApfaiFKZ!sSwD)`GO)_BwmpuBnW0zA~7xyG)|GUiNv;0Fsl)XX_25Q5=n4v{2p5X|aCV%{idibc{T5__6p)*uqgCP7mw z5}!!YE)dK-B8k~7Xxt*{5lKe6VAd=W>xF`*LLdh(5)|1Y@rop2i(pnI5@Uv-af+l( zB(_Y!tVSfJt%9aVBpo72-X@sUiNx#>G{qw65{W%aFl!KrWxJp$6^TzIX%`D-9+AXk z3mUgbdPI_uBbYUd#CnOKsSwD)9fBfTBwmpu8VDv=oP5j0Mbw28!a zuV7Xq64QNxrbr|mB1x_m%<4p9zF*K3i=;~=_6G#B29a3)C}>JW;uA?)jbP>xNz8+S z#x0T_kz_n1m^F*U`mms>5Xiw=L6I#IuSgOe5zMMYVtiE4I7QMX65C^fS&c|cb%Lfy zBpo72eq1oC6N&i=K~pS}E|J&|3uX->vD6EiQjz#XlJ+OT%p;PRCk2gLBt0U@I3k!e zi^SR>XetD9@F_u&EfTLt5}p>!szhS^v!HQ`q)jBYM!~E`B&KHsO_4}CM3VfhU{)s* z^HD)lERrsf*gb+-gGemT37S%o_(YQSykO=LNz4m^#x0T_kz_OpX3Zk8z9?ua1aj~t zL6I#IuSgPJ7R;(dVr&*PPLZ^U#P*6{RwEMAtAeITBpo72eoZi|6N$M+&=iZLOC@q(>wf#{{!xkyzgnG!+6l__m52pXqI+C*aei(pnG64Searbr|mB1vu&%<4p9eoxR8i=;~=_V)#|29a1k5HzJC z@rfj@T`=>AB<4dw;}%JeNHRVW%$h}F{aDac2;^XgpvV@9S0o9a2xe6xF@7p&oFZux ziS7TGyB~Nr=llQvIe$tHMNp*l&vhNGrd4gwYFbB|YO7JDDMdPMB?B zoyA(Yf+DtVf+8p<=!mT&C}O%TC}O$^il7K;zV9pVcTOLT9RId`e!tvq$LrkR&u6ad z%KtRywBA51N!T_a2@wUt^H0=Lg#BMg!bFkqzKL3z(27VRM2Yadg<6Jiyp1GElnMVk zsAUP~W+ZVS_AY_|kt1C1p_U-5?;{BkdBR;nElJouKoTMfgy%!lQiS~@Bw?aRc(2uL-pb;b=w@CCY@q2WnZu zxdW0o5Ze(!fXERpD{2YC+JYoVByk`%3_*a%5w78=B?zk%Ns!1B?t@WF61GE-gopy+ITW=NVIP4c zOcV+4NYv7Vb{LWfQ6hY!P|FYw7m_GZCj6sO%M#8pNa8^3a0CG&N4VNhOAyv0kOYZ5 z;U0@xlCX_K5+VwO$BkNwu#ZO)CW?gjNYv7VHUUY5C=tGisAUMpBqULyO!$vNElW5j zBZ&hs4}t)ZBV0$LmLRNCkOYZ5;XVenBw?G1Bt#Sl&#|bb2>WqJ!bFkqPD3qCXkH`{ zqD1(nqn05Y$0LanWx{^~YFWZL14$f+oroYnLH zMJ+*C=OGCadBQy(wIpFX6G@0D5T3J8OA+<}k}y#uybDlE6WZBGB1DPsor7A2a4bX; zCCY^VT-36Ja}km_5L=8OK;#Hl5VZthJr7Bc$P?}*s3i&8`A9-Uf$+4WmLlvIAPEyi z!uuoC(u8&)k_b^Ed?C~_gySM4QKC%vFGej(I4?mG2VzSR1c)5rx)ikpVf`_ZAdx5B z9jGMi6B7a2-j7pB?#*;kOYZ5;a-MXlCb>}Nr)&Ao~uzy5%ymp2@^%a8$~TmXxAW# z5GBI*Yt%A?V>yy2Q6~H=P|Fg|Ymvl(SPVgc$Pq3BwFF^}BMB0D!hIcTNy2tLk`PfK zJU5`0BJ3-Xgoz^Iy%DuEq1}WeLX-&K&8TGvM*>NdC=>o$P|Fg|-yn$tvEL#H5IMrN z3bh1b{T-4Zktf{0M=eR%ZbcFz3WO(#T8gmWh9pcB3GeNwr3vj0BoU%S_*SEqAslxi zi4tYPe-~<5!g)86I1o!A2oO2Kbq{I@!g?=~Adx5B_o0>~Y-^B&hyvlcAGH)=e*j6C zC=%XI)Y62OMiL=PgzrJrGKAwHBvGPF_#Z|sOE}jei371eAP5jS!u1Gh3Bvj)k|2>M z+!@r8gzYgTA)-Kd{)k$Nu>T23m?#q7b*QBY?axReM2YY{j#`FrJb@%ilnH+pwJhO$ z5=k70J%u1Z1c)5r%A=MbtS=%75_!V?5^71p_A-(X zQ6M}UQA-i_SCE8>BH?`%wKSobkNt7rP{(qpBC7f>{i371s2m(Zo zaQzdt1Y!Lbk|2>M+;5_mBy2?_A)-Kd-a;)!*xyDHCW?gj9n{i19O3#9wFF`P2uYC06YedjB?;TdNJ2z`@O*+=im-o* zBuo?uZyB{Tp?!uVLX-&K=cr`}#}`PVM49k!MJ-D>zeExTV*f@EAaaE3E7TIewbp&N z{g^+9@AKQfH{1lK{h!Wx35w#5A zz%^h*i8A4D!3MH~b0;KmAht7t0FfhHJyA;#)?JVUi9F%n6}2Q`+YL#GC=ebSYAM3L zJCZO_B)of|mL{}4kwl0R;p>H3hH&hKBubPC|K6x&3FkgY;y}!fAVA~@S8vo3gmqse zK_XAM_d_j7*!my|5e3527qt{&?}sEz6bWyC)Y62eA&C$r!l$E_AsnqpqC}bS?~huR za1KBc2Vw&e1c)5rIsmlrm7ZgmnaxAdx5BBT-8dw!@Hw zhyvjmg<6WRyO4y5BHM z+_O+i61LNjgopy+IUThWVV{j8OcV*PAGI{0%|Q|&N`&tW)G~x)E|MrwCj9eI%M#A{ zNa8^3OauWUN4U;HEkRfVNP z;R&IZBJ39-2@^%adogNhLc0V>geVcdrKn{H$E8T3M49ma7_}_n>_8F+VqpXUB1gC` zLoGpAFGmt2@`U>*s3i&86-Yuvf$;nkwG?6h8ImwjB)mUIElp?!Nh$s-AU!#^H?8}ja zi6Y@$fm)i-u0;|dN`xt1c)5r z`Xg!y!uls9K_XAM*P)gqY=1@)A_|1(anw?T{Rt#tqDXkNsHF+*NhA@XMEIUUEkih- zMiM2;gnvD1S;F}Yk~k217D0f>5w7P@OAyu^k|2>M+|Q$yBy4{{5+VwO=LOVKgna{& zFi|ADe?=`#Xn#WzAxebr@2F)6M;=L(C=>n{QOgp}mypDP*vkk4M2>K6L@hyBUqKQi z@`U?U)RKhlH6$UTKzItMr3m}$NWw&s@csj}G@-qLBtn!3-zL;DgyWw`qC}bS{|mJ& z;d~QG9EcSW1c)5rdJDA#VSO7(kjNA6cTh_bw#`UFM1k&WeCTINTNiU@PC9_mT+!C5(i=*BM1;V!u1Ji3Bvj*k|2>M+-1~~gzYmV zA)-KdK1VG@*uOv$CW?f2D{5&%`w~fnC=tGYqn05YUm=MSW#C%>eqBGpzc#z=d&AiP z#DQ2Nf&h^tTurDY2x~KvAdx5BJy1&$wjGd!hyvl+5w#Ryw;~A>MZ(*HTAI*yLJ}cL zgl}imGK8Zik|M+()67By5wBgopy+@t~F>>_;OB6Gg&11+_Gx9fKr7lnCEc z)G~zQSR_%RO!$vOElW73A&CPqFMVG$!bFkqo{U}&)9B1gE+K`lX87a|D~dBS}zYDvPj2uX-25T3=Tr3iZvNth@S-t$mP z6WS6a5u!x+&POdnINFg!i8A580JSXP{1K8k5W5gTfXET95NZj+dJ&Q!ktf_2qn0FW zmmmod1;VowwG?5$6iJvU65b!9mL{|gBoU%S_`;}V2*+heqC}bSUyfRqaQ*~I9Ee?k zAVA~@*H2MP5Z0d|2@-k2{d3fkge`(3L=*_mm8hi%`&CH7M3M0R0<|=uEkhC^N`&v1 zsAUMp)kva5nehJ#wJhO`B8daBYY+s89O3#kY6-%+97&MK6YdqLB?;TLNJ2z`@WfC{ z5q1Mfm?#q7IBID^yADZ&C=tHvQOgjH8<0eaGT~o|T9$C$h$IfgZbA?sa)j$<)Dna> zfh0)e3HL3iB?;Sakc5Z=;rT6UDZ;)ANth@S-ru2?CbZupi4Y~icPnZc!jVK0CCY^V zHq^3&^L8Y0Aa)0W0FfhHt5Hi3);o~|i9F%H3$-L+yBkS}C=i|$YAM2g50WrZB)s>c zmL|0OkVJ?Q;ah`RhH%`EBubPC{{yIH31=sgI1o!C2oO2K^&n~q!uk-BAdx5B52KbO zY-^E(hyvmH18OP4{s@vVQ6#*NqLwDK43Y>@B7BdbmLVK}L=q*+g#S;dWeMjxByk}2 zX9NKvN4OqGEkRhHKoTVKggc8`lCV9ABt#Sl&r_(S2>a7W!bFkqu176RXwM*t5GBI* zENU6T@f?yUQ6~I3)Ut&0c_eWl_7?;JB1gDhKrKO7Hy{ZTdBXiy)RKhlZ%9H!f$;nt zwG?5`BMB2l!uuj>X+nDmNrWg7zL!zU5RQ#VqC}bSzk*tpaK4Hp4#ZwV5Fm1dtAJX9 zu)dBYNaP9kKTt~&wl|Q3hyvl+gj$NQ{}V}=C=%X(p_V4JH<3h$65%VNmLVK(A&C-Y z!v8jES;F}ak~k3Cj37Yd2-mx)B?#+#NP7a)j%1)DndC3nW1zPq??D zmLzOnA_)-%!t-y`QiT00Bw?ZmTkhL0I=f5+w43dvDZ|gl!)r zA)-Kd?5L#(dv7FRqDXl6MJ-Ke`yq)CCBoMSwG83tizG^v34cG-vV^lgk~k345Cn)E z;nGn{5Y|>CK_XAM_eU*B*ajd85e33C5VaIxKLAOXC=%X5sHF+bfh0nd2;X4TGK6CY zk|q5Cn)E;W`|(1YvDM5+w43 z`v}yMgl#O65K$mJ<4{Wxb~lnRQ6#+MQA-orkw_v$iSSK8EkigaB8d`Z!aoVMEa5x~ zNgRkxMi3x!gv*0kg0LQqBuL~5_Y~BUgzXq4A)-KdrlOW2?8hPr6Gg&%9BOGon}#Gp zln9>}wG82yjwDKy3IFk^WeMjANa8?j27&;QBU~q*dhc0B1gCuqn047K_o#UPq@!RElJpxAPEr#!gD@qDZ<{4Buo?u z?**u(3GGKnB1DPsU5HwSaDKXyckIwh+TppK;#J5Qq&TJ^-?53B2Tz~ zj9QYgbsz~51;P_XEk)QbLlP#6g!gjP(uDRCBoU%S_^v=LLpXklBubPC|Ibj%63(9^ zi370+f&h^tTvwu&Agos*2@-k2{R`BRgl!p;5K$mJzeFuX*sn$sCW?gjSE!{4Es7*U zlnCE7sAUMpuaQKFGT~p2T9$CGKoSRH*CGfIIl>h~EkRffBtarixZ|iL3EOo@LPUY^ zT#s6cu-||rOcV+4O4QPXb|aDqQ6hXdp_U;WHzSD>Wx}68ElW6WK@taIzd;Zna)j%* zs3i#NDkMQ7Pq=@FT9UB+9!ZEO5T096OA+=Yk}y#uytkp2CbZj;M2HgMy92ch;aH6% zN|Xuzov39A=UqtRKe>pe(kp_U2ySi<65;zZY8k@uIFcw)Cj3vJmL;57 zByk}2B!U2uBV13RmLRN8BMB0D!o41~Bw>37Nr)&Ao@Y@@5%%Yhgoz^I&7qbiwC9mT zh!WxZ3u+m{@dA=4Q6~HwP|Fg|zaohPvA-b*5IMs2chnMuHIF1nxVIRAkp4#eI-5Fm1d zYZGb-!un4nK_XAM|AktTu)T>SL=*^55w#Rye+x;NC=%YcQA-orJ4hl#iSTVkEkiio zMG_^-g#SI%vV`+}Byk{CLJ%NwgzE#;5`^_bBtarixIaQIN!Yd^2@wUt^D$~E!u|=8 zFi|ADpQ4r~v@((iQ6hYwp_U;WpCgG9Wy1djYFWa$6-gY3eTg7I6+QI1oD+L4e2+u0v2u5Y|JH1c^N19)Vhtu#H3#A_|1(Fw|0n zeH4-~Q6#)B)Y61D8cBpG5xy~~WeCUNNTNiU@VB9sC7eefi372*2m(ZoaE(JPL0IvU zZv=@v;U13-BnjJ*NJ2z`@Jv80Mc5}I2@^%aI|;Qkp&f-JLX-&KWYjW*!-FJBlnMXQ zsAUP~6eMvVb_{|5kt1AFQA-fkW03@jJmEeLwIpGih9pE32#*)F6k(r^Buo?u@A0Um z3GD2Zw_i1!f^(YC{ZT-b5Y9@&Ur}UKx{sO z0FfhHXQGxMtY;w!5_!TMKrKnw79a@`1;TSSYAM2g4w5iYB)khzOB33;NFqdu@GU|u zLpT;Ai4tYPA4DxnIL|{82VzSQ1c)5rIv=$JVQoheB=Us&0@RX(?MFyLM1k;Jh+2xU zhmeGcBH_IVwKSn!j3h#o2;U{BWeCSoBvGPF_%B5*OE`awBo4$n5Cn)E;R>UcAgq@m z2@-k2eK~4L!uAs+A)-Kdu0SnC*nf&7OcV+4&rnMf+Ru?hh!Ww8pq3#VS0afLWx{_I zYFWbh3nXzMwhTdl$PunzqLv`6S0f1$dBXiG)RKfPiX=o72+uXBr3m}4k%WmN;a!ee zn$T7ti4Y~icP(le!VyCfCCY@~KrKr+<4EE_>^cMiB1gEcM=e2EZ$J_x@`QUOYDvO& zBa#qNAUrprmLlvoBMB2l!ka)XO=!0ui4Y~i_Z!qQgyXkJqC}bSuR<+LIDdyE4#a+s zAVA~@*R7}}2x}5akjNA6+fYjqw%d_}hyvlc1GN-kUyUS86bbL0sHF+*E+i46MELGT zEkig`NTNiU@ZW=4mT=ySBo4&xLl7Wxgli3I3Br0mk|2>M+z+6ZBy62XLPUY^q)|%| z_6L!Ki6Y^B2(>h!J&YtmlnCEi)G~zQ4@ja!neab?T9$A=iX;xiG6(`hj&MDOT7t0t z5lN896Yf8umLzQJkc5Z=;rTOaDZ>6Zk}y#uyicH(CbTS)2vH(@PokC~98V#M5@o{w zG-_GGxgJRzh&_WKK;#J5v#2Eq>vKqgM4oWxP)icF=aGbn0^#`!YAM400+KLMB)l6? zOB32(kwl0R;rknE8N%^*BvGPF`17b`3FnJQ;y~;r1OXyPxL!srL0C5;2@-k2{R(PH z!uBeX5K$mJuc4MA>;)uYqDXjOM=ecg|3DHUN`&tX)G~x)6Ot%VCj9?IElW86g(MEd z-b4@}a)hghT7s~?g(OJi3HRHmB?;R*NJ2z`@N7mcMcCg(5+;g-_dV3og!Vp?2vH(@ zCDby6;{zm7qD=TdL@i4=KSB}*Vp|Xdh#cYi7_|gp{RByn$P?~QQA-lGGLjHcAUvO; zmLlw*BMB2l!uthkX+qnIBtn!3-2Zvbi;!Z8p@lqeJa15nEn z&Ou1xK+J(4K;#J5VAK+XbqJCmktf^-qLw6VLy?4t0^vCbwG?3=h9pcB3GZ;!(u9U5 zej`GZ2;afjK!$J}f+R|m3ICy}WeMj9Byk`%5j6Gg&%G-_!=n}Q@llnCE3sAUMp zR3uTNO!$vQElW6$LlOsK(+~uR9O3e!mLROtkpzi6;XWRXdh z!bFkqo`hPO&`w4YAxebLhgybk%tR6;%7p(E)Ut&0R3vdAHVZ+3$Pup7P)iWj(~$&; zJmH>=T9UB&k%Wi>;hBS4im;!7Buo?u?_AWet{%HlnCE4)G~zQ zmq?;SnebnYT9$DB3P~J@MG*vu9O1eKwFF`PHIg8aC)~?XOA@vfNJ2z`@LY>pim=C! zgoz^IHBd_vS{zA)C=tHvP|FaG>ybo>GU2}gwJhOWi6johZbT3ua)j$9)DndCW+Xu( zPq-7PB?;RtNJ2z`@cag~6k-1@k}y#uysJ=46WZ^PM2HgM`#owI!f`8-C{ZT-Nz}50 z^EM=LAa*-~0FfhHcc7LatgDd(i9F%H6SX8^y9-H(C=i~zQA-i_6p}DeB)s>amL{}& zkwl0R;kysD3=#fVf9&UPt?4Je`ggvyMjL)e%a_Y6A&WRoH}p5PeOeYRl{~(4{F_?; z#?fEQl@6F4aVj-hEQg3$yZ*1*b>q6Xw8_)EHdi^b#qtMHYZ2eSez@H18EQS+V6p7m z&H4bY8wbCwjce&TyK&Lm+NeXjsJ3>q*xFv=`=u)mtz0&{TDPj%oEfqFl9xteGx|GX zt9K4m2W2dHNBgSfCle&kG|t=1YsR={vo;**lbf~Yu&G<#-LCxDyV{`fwFmg5IKW-R z!K_|5qPqjEtaqKy82p|#s-@>a@`&ad3*OTv@BXzb*SO`a?OF}*Yl9j$JlZ+reQocC zhO3P6C2`>Cx8y#rGA|Mn$b+f9W3+!N*WGHS z{w*C*E|jH9%57gsXH{=Q)5yy0HuOumUY%u&TwnWnWxd0qzOgKAkb(OPd4}rjZr#=> z`x{ihI=fr&WF_Z0dW+;eL6i-e29(dWm_2_^MsEb*&pyKGufqSlXp>(Ts7&weH&_ zzBhUv-_W;1-7x9Bj5?Mes%pQTTfNzJ4McUbL1?k-q!ijGiGl;wYkzA zn`X&xs&kbJ0;kFK>g;aaHBa`os(y8Lw;n!I_Ve<9IxOlNOHI(VzFF-cb-Fxbb#}L& zSJ%Kwb*9623o2Gs1SW>L*67R%nUpqyKkCn~R1-k?17 zJlPw1zUnWLvzKYHe@nY61XLk>mMmx@Gf&l5fdT43OABN^^kO+(YJKPqM^zroSM-o` zp~@$!IpR{;&tJ4{n)|o3Um_O~1}9>Bx@C5nI#| zR;LK+t}jzNSgCeUo!zakP}|)QlH04!qFUb?vdUm<$QbjP)~_R|Ua)4ESBp6PNxl4s zSIA!N!!xJWSE|`_rR;4|Zi`7zy;jb+$_J?FyhW}@uCL4vi~7bg<0cu{q`4Qn^#jw)^Dziq+d@<=D_Ur@S^Ty}o+>N2OP(Ug}TM)<0}NH*{p= zLj0lar|&W8J`Zm{yIbF^`YF|~&hFMntdraASf-AsI;%m|)tUICJj1-T+t2RSm#J&O z`=IPsr=~9OCb`~WQQuhFUXVp?gPdvQ&1x=GGrw8p@uHkd-%@=w+tpn8o?Ku3uACE< zvuZjjQ{4Y^@5{ov59HijlCw?C>iU3Bk|jd z4X;!ORGryT1KQ4RUY4P%W%f*MPsD%&XI>F7Xz%zNO!_SLugMdD|!7ARlMm zT;gy{7d z{VW@vln3CbDR}nk{9}`TSVPC!`SM6sPu~7caGf~AWbswIex6vHQfGa!SQ}esJto#p zsk45mSQFc65<4(1?xByJGIfYNkhBQQQ}wC}_L1x7x6f&xKf8U&g84F^sQR_fSIeSC z;|}_;rUAb?tn#@>F?pEzxkqE>*3Rp9&=)oIzGi^Dq~=kXr-9#W}* z*33`9nlG&M_qEJYXDEqj9z@rMmQUX}szuc-vyAgv^x@!bE&8aAu2gNKaR+(uwd)Uw zgE2p*+jOhEa%Uyw)YKfIW?AJycx9m-Rc$IOz~=4r-bJL#`AExY|N&C%D^!~o&AJi50h@6|0%WAGw zbA-x0YW7q!u4Yd4W+~&tt$BawY~58qv!TP?M;_9dJL{EK^u=l}QS%ZtuT=BbY9`dQ z?Iq8DyYl^NKCI?rYCfZ8UQOSAmGgC2UQr8gsQH$f3-^~Bj;qd7gd&$nN&SgISSU9bAv@@lU-zp*d&-*o`rSgh0guKntP)SKr1yDo8cgVk9* z!?(HGtIle_I;-n-rhJq29g3AZXPpgvul3sf!`Wcc3a%; zUc2o+Q`@gSz^bdWw%<{^@ZWNGJFMA$N7uc-Cg{3T)~s^6_6M_+F3eAAbJ-zdZh{m!R&Qr2bX+U%7_9_W1ul zK7j5Y|J_|9|J?(u^Z2js`2S@7FCPEj=NkG!kN@wpgKi%8)jRKZd;I?wcUal+w(Wh- z$Nvw#Pi)&^&HIh&>;Dhk@PB%~uRZ?%(+$?1zuQYL-_U&fpNI=|cF|GQqI@8A1Bdi-~LU}wmO!GGhbtb3J6Kv{-H%P*jHAVJ%Qjv# zSnn9!Mf24_oP6RFBBz+&?emc7yG)QD13!N>651~6vts+4?JqqwO2+; zto83^{V=iKb(i5~^imrKjPF#t7#H?L^UaV_e zHx?XdA7tHfq&!T+e?UWT#{`Mm^Ik5_J7l}_zIdR0TvK?0xF*`g^(f}yL+uB3)SfTZ z&9STz>*oEcwr{SRzeP~Ho)+s`o%M`ZH$S;m{YJ}N#oha1E#^jvg+q)|Fy2 zmkhUGi}l`4`!w9a#*ffXuG|yM`*&;gChYToywrBF2lG_@@Z8bgxPE~BIC){s-=As{ zhi9I%sU-Gv;6VGxj%AtpXU#t+*H@{z=~d~?$`hZLo{^I?_?nzsRnNLf+W*S-bLi{R zrI#wR!=k>iq*T!UvMf|*ck2`XA$!)1+t2RSm#G8Vqz*_<@#u+ms~KnT|046`<%1Rnmtb`w*_&LI zr)BekjEM@EXEYbh=^Q0Lwzl0Y-A7G}n$>mt&Bhsr>#@=AOp(WSym@AEdP01e_v_mA zbz8D5~bE`r{t)qqK_456HtZcVV8Y51mzMahb#;rE$x8 zwF)kaY58A_Tm(NKX9+SIH{K^*pYl~s zt{;BUW*_}+7v~MPyg26DI`gzyxqA3tDEFxx{zlOVsg>>y-#%V$u}5Wl7K`^gAO3@r z^g;Ws6OT~yoVAbKc@G$$Ptp%)jy&QL@8s^%`!+mg9C?&JY~Qtis(%L0pN*?TZr!q8 z=ADHl4e^FOdv!|A|Iz$K?b`6J$9HauKG=BPqaQW;(~0r|R3G2}u5ph^GB@-E+#qhfI z=F{@xz7kUVu0C)4Q`vm&Fi#G(@9M)RpswtIT92z)y*5+Ib8DU&#HAlKxb}j7d6c}M z)yJ4+vbtp}_l0M~?xU*F-Qii)IjUO-|G>lZo}>>kTBquJjjTP!H8sy4eLeCRcdlGL z;tDctoOjHEJ&o{Gy~U>vsJjDps_#MIDa1B9|)fR5`qViB+pw z>F)3%Dz6@1_6HtbbecZx=-O-V#$)8+RX3hcu0AO5QQk!zzU=||{=-%|{Ex({Q#HCf z{EW)0&trujc=#o+KC1G9YY{hTWU4&u?si&xla_zrP7BlZ$-Q4WR_?6&SSVIqxel7e z;RMx6cZX9}dG(!#?S1+B{{x<0hU_?Mq`1~UooI|XLA<_4kNf5;!ZJkvxOtV>zQ+7UtaboQSSu5@t14MD&JMxOE{u!nESxxv0x!(4cPD9Z~tLqPv@5Wz7L(l@sbtY5sU`e8;Y%D;o*! z_P?E$ZuZmhzuxh;Y+pQt{>PX6o3}6SLf>5Y{&{y-b>00`?!w*NHq|qHuMLX3c=deM z`Az4q?7y~9wWbd2(c$uGcBc9GF;C)2-hB10U2hTV=3f}8UGE{*53REKbca|s|DA!Z_0HEX(RXV;rOP5SPqVr?z(r!cx5#~a$VXf4i%xn^x!$gF zZ?DcNVf}$29idS&aEz8SJ`;=PO;dY@jp7XE54h{C53IBPQa62b{cC;mUfN6CcIF44wL2Il*6SV6 zNU?7I#jx7`2(fPd*}8VUO{|;mTx!?Hi}j9!>jaZTpw(GFs+)DESf5m#Uo7 zbphnBuT^h?ej+e`+EaU^J;nMUt{eBBAQls^5eQZ8+FyLtuFn>0=B2G&A1iM6zIE155$opP zE8CU5%2{>3f^ukqJbx-6XGzWui$^W2RfU3@Bh+-9Ezht_^_rCjC=Wb9J}&2}%Xy-> zI?Q*twd)tuUGMzSz4|{I^xCrd%OmD5m2|Be7pUYvq*FXh$BtE+i+{ao2!y-3cXYA#fBv&t=t zW$spU(vl^MmuMG?zc)EwTQYyn^3st#mS1}0PMy!D^&t(7BYtgs{-F4qV`0%Y?+(^L z^{9_Mu;K9KhiCS(w%so`XiR_SqD{Z84iM4ms{F6XB6)d4EcQr@iWyg=qxD94o(s@JY;Ki}A6 zt^Tv=^XAFh{SAo)=%{lV|Pv ztKF=dpW;lc(|=E_9aU%j6S0QF=&1a?QL$$ERD2yMzG`>;g;?{{S#J_|S!}3lJLc!u z^|sR@)`xvQVj2&F0&z`ueWagCDGb-^HT1@b>p^- zK3u=+uFc|D!&xY3i@VBkJ^qNloJMXS{3|->kTGw6TBh zhDjZ>R>;T0nrr2>t2s-}w90KUnU7F&m6{ntt~=D6rRFA;TjDbBqvi%Rt=Cu9J1lM2 z$wE*~tD0@HUXc%OCwNBsNI!hh8@xe!@^fHG2S?|-_cH_3! zxwHSQA7?(}J@jY&u*U4A#)p5_f8S`k(YXF`{Q$k$BX2;TxN*#rRXi-r_Y__0#_NxZ zU-t1Pw{3686XM?+Sa!d>bh!uQ9H6F8&7{gVD_c8dFQU9!d86uil$WJt&+(9)Qy-Kw zs%A>&$6KbVLQu_|D)f9EFbamou?eVsHP0IlMyYuy-~6(5#&QAFlxllU_4 z=(Xz^v1VRRwd;>|v;Igo>$iz@^A8+qJB{L>_W2;IPwRSuX{tW;SXYga7tFZk^ON^9 z4)4>@+t~P|UU?_;`IGwCMtj;A^OSgMs=g98ZSEXx{6hTBQiFI6eo7zK&=Gl3ZXy1Z zoST&G%Bz(9>t(+589B4cJ(aIe4*g1ArPW{BGB3ON_Of>UDYwkr zmT~lR`pI_Ri*h5mm*rf$QEjyNobEWSyL6|WPH3Mq_Z;mE@t^i3bLP$;v(pLUcr6LP z+_?GsvgXNrMm3+PYuDSv+J45D=jn$U!JKYy`MvrFMNTrV$?5wH-KY+t_7Apw{wWVG z|Aw52x5Wd#`b*c1Z;UoSO>OD=G}RdWytvN8McJ+0mQ|cr9ED|_%FS(=?)q02jC-Ef zFC4F{BRkg2#OY=6W!|#sEwWzw+q@gp`WiK(%P)Js|H1aHvb{{rd1{8#^s3plH{-#- z=;H0@G=0-Ims+U!ss@yJThh>=x2B;vfrcKQ@m9J5A z=s zcL4KL{ggjC(761s;&sY@oV@1Gk+J1S@i^W|eBZThJo#7s?=9PS+u!ub_AaV(4HD-v z-=1_%{kuM+x$^7%4eN}1d$x)n{k^X_TNa!p_p-=%@n!KI>V@+qml(Y_>f`j4mrBl6 zTYE@s&3wzbL<>igP!}90LqgpNv%QKy7?EZ@WT*r%wGu1YJDYjug{~y&Z zYt_qV{wARLxT;;hS*)4QvG=O}N#c9+v`~Ca5MPI0B)7A`TofmV_%dJS)cU?%KbK)u{RaeXg8K)x2=D-2U0(tmesl<7)1sYuy-O08efX-p~T$F+>S zs_Xa)`s|iNFO!^aw7jlQ-p0a&|V zyy{oM!f(ij@il5D)Vy2G$JG3bny;#vQ0ISB`9n3gs@bwhZg)>LH8qFI*i)CMLhm(=W~<_I;{ zsM)OMJTW=9;(L)W5v)mOQedZ_7DRO{+H!E9}*Q)bvR&#ZS zDy&iqBb1jZFIC>Crl(2%kabgooWVvp<7$pjbAy^&)m*KnTb+NF@}!|^K~oDJHH&KY zRPzco%WB6NWt(|^;}6g4=jgATDj#9u{ZZw#i+G|xKzz6D8ENMG;t$v9j4i($KYXX?bBq4hsxcV9!BUxk^4R4<-M%GmFMs<|VJ6n6iwuqJNO-F=`^X_czW4KJN7O(l0 zt6Mw2)wCjXjDV$rq8&)!b!^aeY}ob6=ZJUQaf2Q{q&8!(Tkz*!MGiSW8~L z75|Yj{WE>qPQ9L&&o@Ue?o6E6+M~g^`*ZPOLhZZbE5(M)KSI{7FB5C#r!}?fSBo|C zL*TA;L;pfw+|l)(SVZRO81Xe(eATX-Yv18b_t)NYj~FbU7pia4&G+Kwn{>6_Xjx$F zzE%9v{Y|P@{fyuIskM2H*MGm*(PyQ)O4YQeS-L^47u3wDnNc&PWv5otk+y6Ka;#w26M@ol8M2w5biGm7U5flvk_StkxsS>(yMU z=4Lhfs9x72#k@Vm$^1M2=3P>(%Xco-Kfs!S`9WLl8O%R|n;*=5%VVJHF=M`7non<6 zsQXaupWqT|J$$2h{WUh8+R$faHY2aJ+&VeivT{yTv-U5QJ|Q-57hkpO>%^LQ5xUl| z9o)KjK;ap=wb}#Os@6A(DPCS$uYI+(Rd2jpKGIJYn=wy+6JO>Zm%G+G^@i5ndURNR zEPJ!fk~rNdzRaKC*IOS@XZ@~j`sRAQ{@r5Td=XIF@32&NYz70j1zqbYv4%5jw_dM* zUpIYo{p)>k*Im=i8O(L_K2Up2+%J~uT|?&j*LPsCJkU+wTp!qZ=Z>u}H1GbU`b4t& zsl}q@yT9DOackuhqN{uKS~b>uV|Sr>VGj3c(cdnUw%H6N6<>$iwC^UB|Nj6BfoA0y&eA+VgG3ezRI9HOAjGrtH^xW>fLDvBuN0T1PhaX)@m4ul1;=Rd0?p zjybJ$VB^vziy;X2m7=RZ|VAI$oQa7>mX3?D|q%odHtVd zOz+$JTuayIOPz!JwLa0<+}2yXu{M9JWo@Iehxn`gU;Cu8`T^9Z>chShI%n#w&oy@Z zMQ!&Cb#Q4h4-{Xu>ko>xUUk;Zr>VW`tea0eEp^t*Vr}m8Qrj$adt=I?IR?$~^o z?N(=fNjLpDVjVl^+P?X5rTJ98{r1Jvj`;zh`Sh}VAb-7WWSw$HwHXUcm<^@{8(-XfZBNo&^+ z66<@`SsyIc%`3RJf38@o*EeqvtZ%yoFBF0KKDKs4=5J$~f2^oopC;D!sk45!xWW#t zv;MwVAN93$aSN72VBWN~JNQVf*W0m8T;kz%`a6pCF?H6P#rn89>wh#4NbLV>JN}ah z4ym)gPOO_B_17NggJRwM!%6M>NU=V;&idJ6y?PUv`|rAwpDP0ME>*jsSz_IMR<2#2 zA=VG8vwn$KuXhueKdab(`+jBrmbh3npB`#=@Vr>7cTKz~*3J7xZNDJa%-8hV^?k*T z&6{$=Y1_XH%%_}3tLw(| zLt34+E%UlF?~dDA`hl&3dbrOJf2XVR4_7txGtNG+b!gRo+G|DPv$+&?02nqzBRP2xt`*Uf*n%G_M-`aa?sH1B&|>z&h`t;2Wj{!@GNAMl^uSy~9)HuI;@9ebQ0 zcUS$>&)>wZ%wLP_I?v<;Iq}<-EeYHceuA1#?UasbqYF4krUr#d5p3?eibA0|p_1g#D4_X?hOfa54UHtD3 zj_$nbnARUPbWEKok0GI^$0uE#wd?CtUY*NMmHmic&H>7`>k+lCRr_)tX<0c}p7Hg<)kim6Vm=vcfX+f{CVuhNWd?`TOk449ukO`+c7G|3A-zYxde}uf6x$YpuQZ z2i8+v@yujZT_0#^_~% zjOEw(^qV;mg%z0M0yoYU1!z!vQ=ECmP`akT)QR$jo7!Ec>fLjPxL3SXw+LWOrL*rfRH7BCfZTP$0Ysu(vY!XOV`r7w6I zu&CyfafUUZ091g{AT~+ihefmDJ|J5 zJb#a!ht2-{`FjE_+E?tYU?DPieC%IJR6*PyOj4-8a&as%93$RnJ!gMHw6bE#TUw!v&W?>(4L7# zQt|j7<$6g-c7-Vduq6r^5Pc8oW*qVFde1KZ7Rl_@4qNKHIGmr8KPc%u;> zko+Tj75)bub4VuL8fT;h%~lmrUXiJt={W7b(HLl6*oxwEvA4177<_BIG2OiJBz=;L z{Sioyeu~F-$g<-!YO>L}*#3iTXIHK{c>dQ-4@o8#x;#ws?yxHSf4w6s>FMXmM#p~D zs^gd4HB!vq1LUD+^T!oOPJsgDgl6(kAh;Rr_svCo32|;f9c1xSJL76gCf6X3D%E8D z(6P}(<45@b zX$ajAsyI=>*$UpN;Jpeytl)YDH!AqNg6dP1gY)yJ-*HFQEq4@+ESkBrT9<#c?$1P(EmTYT>;bLvrub&}nPH4g$&Qqj#G*p}cp}q`IElY)TA{#uJ4yYz z#|}4{_z8FM>ZP&k75-iHh~rWOLA!dC z?9Mb^7oHMyryt-8YU^OKz~ayyan4Zu{!m3klj-(bjXQ&zNB_*N##O=1^{31>hX1RX zFF_4j`!IQQHue(FUMbr!Rn^6pU7W0cuEcxVz_$XpR_uC0_Q8McnY&Tqubpt+_^G2u zj+uJh_`yT3X(1Jq<kFd*j$ObhkxI@7@1ve^ad0W!;P|%Ye;hQejJQ@EB;r~x`*b4g}DyGL0VsEBV zbB(^iuc#GAHr+qh7~9XAgh=?)5xSkgq2ERPCxPSJc4__PINVedQE0@Ng4e0^^^|fu zCd`5pV!|9ZS-nDZ9g6VhbNumrEPs6UW$<;t^WpW<(~;W|pj&sz{(AcMPUGgFyvg$WPxQtUMq+<$M3JnHs{()ct~`ITy2w&|CzU@F z1LaXhb7P-chy_ZWT~@zK!F>v*s;{e`=pgg=D7**uQ2Czn{;*!rXDGT%d=2KMc8=$LXE>s$l}iw%yCJ8{`dmmc`W6RPX^A1o}LHW;3^eCO{F7?aOCW*6x96j zC`*%i{Vbn4E;f1>dy|q%^Xy~zh;H=6>Rp~mF?xE539kqTd} z(hUl3QSgF-c14$?phLk>4*3XX9Hs6qpIZuwX5KQVV7l=KLg*?zo_)S(?e_le% z?-HIrC*iVRB`jBT>3_*|-XFenJI>0qe?22m&q(Z=_g-#96yNQXHk*Tr`SU!CGz!ok z{}u4*z+242#OS74B+O9hLS3dem?Rt#{9i$Q@#McF{1;uNU%8!r>D4N236Tv6ZzW-Z zg1G_@BW+RyDM{03Prr?S=lzyBNq0=Yeg5=0`P0$k4XtIt&21#y7bc-YrL$BzG+g2r zDY#7K?^Nk(MOUfPU3r@Cxt6Pp9F<{F=>)}~UNxYx4gGkZ@ldc!g@-p%$qM7Dws{e< z-V6nIMb&(=!iY8%kGM(>t;YyXqb{zj%R0ycIf)Y1tMmm0cPdz<^2-&>P|!YD^1U9s z_`|oU`I_1f-&RaDJfq_bSzrR)z7hxC2_0ztN?3hkd)mL!xV}%0s&DMb%%t0<&7LuL z-fhzh{>@M0dpzy%_ujp9(*s858{bp6DS3RwpIj^;d64Xn&xC*C_@J(`zgXvp$Fqj7 zQux#!GC#G~FuLazV{-9EHJ|ZH`LhBxzz-ZR$Ed!WWRTTM!ouDXUXFfQcbUIJ(XB}K zp`WPvxAcN4P^k#h`}h?27rmx>l&$C@uaxv6)DO^N@2CC`8cR%LY3mxpR0%Y^q~Mhbj!RYNQt*BS*GX8cJ*yCJ zD0o=Gm!vVq_LN^S7q!`Jw2+@ ze<&EHgxpTS-U?KzHZjEk4Mla6~>f4_b5~LEcW- z8r)HweXY!SOgSy?82Q6v-)?|HM~4qN_MnsyUrF$%9ZZs&=lB~hUGasP62IlwOS*Pu3Zo&Hs#`dFwFDLg=`I)0^I3XACl}CiA1lz>Hn$OwFS-{HP9_P?}}7 zY+e$t0*^;&wA)m-kzbLqC1HHSEfP_rnwP8K%zG4r1(#;jRmoxFESYankeB0(;~Eq} zp@O^amV|Y8ld;}-)@0Df>!G$uK#LubuA?dLF{78cLl%vC%ox;;q*-^B?Uz^O@%!hy z>FLLefpPxx!6d7+mW>PO&&Q0umIKAZnlARj>SQ!r`KM8*rH+Xf#Uk|60(L zS@Zq|BgSl6U$g%SV@~st(ZO}HU8fcNTfxvrCBB1#y%ijwpy$XaQ>Di$I8ni`6rUL? zeTRa@5*BOa3h}gpRSJHn;Fk(|j*Jef^l=5xD0o4^;PtY>Q3`fc&~s#TrAiMLaG0iz zR)|~$=PG!&f~5*RqTu5SKBwRoKq1?dEU5_@^XJULhm{Hjsv#b(&J8@e%-s#YvImvl z{}f`BZUZUqX&m2uNUNSUUKzY-wPfS}b?OF$)I7wv6ux6iJe53S#B{v!2I<9a;x*yn zkVi3IJiYOZ(WULiM`UgL9+hzQdiv!VG-}^!>a!7d`kKk_+Gvao_Et_`Y&6n~E2XTT zRPaRwUso_mE#|TZ%C_)Omp?P`$E7iK(ioo9{PV8{uGJ;*eCMqtex!#X-#l%Z;la-Z zo^N&eS1=DaE;BElzSv~M6nm4%;?ENNaj)Z#uLh1!WB&MU!1=I6nm;S?ht<%(=pO)% z&oYWnvF2$v&)`w5qkHF!fnB@x@UQ4`DS}SmGj^^D&z`4=zX#KewD@gG5?@TFWcDNo?(02cfp-pfK@akm+GZi)VQ{#{$XpXiTgz#A>` zwDmIJmQH)Ta?X_sW+;55g8dW}tng1am9{IG>X+X^rF$u8vCA=cDE^0^ zll4}lnZgIeE21kDj8V{`pr_J~DxIR>pv{K393A|zis7fxdoRNa^&BZHOHu{-?4skZ zQLPyL10#zj52UL9kw(2)rQHhp)2CV_eS=v-5520cBEuA1;oci;GSl6!7*ou3DYX9; zTw5Bi59hwr{LTUzRb_NG{akZ<6@o+a;*s=pHRu4%+l(9lQ+w&CB55x(t5DW$^q1ORc#kts6{3 zYK(s@`z8&S|CM)et{kJg%4ybijw2=`qj`4n$d zKl~Z)z6{=$t@rH+}$SGlANs1qetE}dWG!5IB`)U{mGj~ zhhkk_H1h1^EomiVIDhNQ|^gow}3H{Fm z|9gJ=f7#GbMR#MbUcDyIzhnBmo`v(~()1n1HD>$Lnpbxi(dJR(7fWG8DwwHYmVyZi zE^|q`Oa+S+T%=%@i`u@6)wTW*4SClX#^K6$vAY2H>bqFR0RHl>(Kk+4F9|VaecQQa z@IRDu3%Z(n-9~5K95#+#s5Sa>_e3H$=!F4X~k#S5QL_%|c&ZZ1{euFK%>z6}1J z%i!M!o(~!CfC#%iWAhh~vS&2!6XQ@Hf8F>QI>?u+{`jL_e9gU|;xs32r5f}k5c8)J zf4s((^J-q*ZG5JiPEg60Moip^DN<=VA&);H_~WrE=EzsSG``deuVwhE@U*Y-{i97^ z8S(nM>zFp1{{G5{A;)+4+S3vIGVh*1e|}~3F(0^rdes?2td1O}C7bA>Lq>b5s59D| zlPA(Y-{Cu%^>s#&zF{K5NE&?5u&v!|#Oe)5T4>r~Bc9Ut8VTktljwy;qeDmrTH!*s zwojrZdvP^=A^v|qPb|mpTht+M5pZ@o^|cX8r}i2#(X%Hv)9}S}0%DWG$rSgs(JR_9 zr8zGhd3ngooI+E+Hu^_bPHoQP8d`H!0Fz+7fc;wFnF13KV?=!Boy77Da zbb4W*(Sa)W85ZjaAodA_Q5=ql^89qBC7}?1c!hT0EHjw*h=}9TfzyBs0^kqFWdU~< zWzlBwa9kd64ZwLe$sE8H0oMo|w{$HtEU%!%w8DIUz$2CloyLA^bhB;;L64hh$+t$Y z;70r|zZnvstG_i8sqR~&M~DN#)-v2M&`k6XSH6z>4Q5>iq~jJEwcqF;yc54i%wk#t z-5$-N>F0VQVghf?dEn0j?`aLkh4L=k+Kl6QNx%gGmyF+9ZdmvT-oi{lDatyKAB+50 zn)aPxqdf-pI|)XVaALj5zCd{LYw7OQ8C3jrbjT8x#9} zyoyx*4=ghBHkxzH=wnUC?;dlwne?$1;`h2a)c1g4^je4CyXG*l7sQM3_HO~M9=Mj~ z;0CT?4lO?b0iMP0%(+4(y={$zWsd-E4}EdUh@;;R7*Wq7jt6w<(h zsJ{xovkGYe@WBW0+f~T4dOC6(X7=_$$UO;xRl@Cb{GidxIv&4Q%%iwNMqF_bewWSj zRp%AJEdwrzHy#gf{|4a7ffKS;xGLbb_|feIZaZ+i41Y%8Zy#{gz+K>o%rHk@3r%|R zkdYE>4~4DV!L(GG+yHg|{SXGF0JxkYiau;~58+JKA$_)prW`hg7@%?;QdY0byJnAPhK!;|qazEawK>*PL^oG}e0HcHT#aj$y8-zpq)*yMjIeTS1NY zQQUFJG;akBJ8txvm43gkOv^yy01m1q9^RKq;5eP9y&P8!T#ptwuD82@O9CzlzdcVT ze$)fs^?o{Z+!z+U8Tq15z$fD`0|j^CDE|k{U)3vV&JWNJ_ey%`2V<1EzKr(&fVRdy zNY)d^40G8knsdVF+^%euQdgAcO1K3(7L~xo(ieXjG1lEku3JT)oG?1*Rn6#7gf^R3 zQOHTuuxk}{=P>yZ8g&v;{?13}?vrRi*9v<1B!c1974+Ll)Ld7=U1xMh-s4PMCa$k& zmKJY)4sa)cD_ax6VyN&(BeuI^wV&`nk`5ea!5^+v)xf2$rdNM7Iu9vFo=31epVOU1 zz6*Gdg>hUEv};8R9M4Mtu6#Ac{e+%YBX6^4#`vF%Saa7kH0LMig=-Bx`xAPydJTPv z^uRjub>2xhfNlhi>mYx4RjI&*uWKGht~(=uOISz48jbFHF7h_>I7dZYs~UOK^(YUN zI_vu$ZRuko=t83rWL~kJtfwH~6YHt}DabwOF`9JB=p2^(7_1Bt3>?oMy^vO&hAWs; zZ-mg6Q$~_G=n4All+oY3;|U5mZS;-a{baN5aQn-_lDqLqy8g7$OV6z2?r-#dd}aIj z(?+7+_!QGB`9v5)4W}WGoM-5t(~v{iGt~WOV^q83=bCvXgI5{knGM_s>iCNhP0##n zv@0&y%)~VyWDB{}fu;<&B#ywtWpx6$b--~R{NcC@z*YOvh2yx#4O~mRvIDmrIFO5n zt46w_%flVF0ZsVo+WE~irOD_Mn)^IDC`DCB)6N(j>Fp+ina^*b@0(!jWiK`RA8ubs z*jz4ui8`Et4n%IH>(5}xSN1kNdj>Mt{x)^^#TX*yo}@(h(06zm_VzB#`o$QgH@Nu( zi-|dbzWBw6H?Me)PXB^&NPnNY|7r}>yY6IKot$b)f5p)6+DT9R3jX$w=rr=pD|S(@ zv#_c?yJ*T;V}@SvDbvo%sD0!)BZ7WAYxL32?&g(l1?P-w&9Pt7C+83# zcl`?e6=IP#6OL#LwTAr$9jmP4gS+)4BA=|^Fu37+X~u6*%;ayFR>dQ(7}^4S^cJKG z6ps;r2f*XPH?;pZV^rwO!%W+WxD%?EO(o|r=EHu+ZxY&;LZ9 z{f^ERo}v!t(V5j}xRSI!f~e)0^G3IT)xR+M{JfE7?Qs@s5i^}Ov3A7%FnWe&{l+x6 zj4;)RE&jt`aXWrznnN{;Yt8n~&?4Z*2k=<3Gu8iL1jPjX)vOlW{P(_S_pJ(Q66$u$BYzf zcz49qRto#u=$ldyX!lOToGE9RhkTCrFyycZxY@vAnS_|M759Ftfhr8N)91fqomlm^ zkq~nssJRfgsRmG3f@Q6N30FY2A$Gd>ozZh3XE`2-6(M$Q5q@jt5n)L!A}QXCBIGw9 z-_wi?;8pt(Tat%y=gENRUqW;5@KUGpaEZ!L_oYpEi3i=hY;i#N}Xr(P!3U*8oE!HW4cxC~oX zZg0}M1mlX4Xy5P2hDO3}Rg<*UXZJRCZ{V1Mkvm z>^N+0ffLFMTorJb(@0i(;&~#?kPGCs|BX;3a&xS$00+?am)19sjV13L< zSJ2ByTdR_xZsK=m^B#rcr*&O>&_4mJv)R>y##lg?4P2A>-PxSilb+zXO5k>g-<{2| zy(F#)xT0Qk+Jdrs6wc8H0a0%nr~|j6x1=ivuAw(Q#Bq*fj_VM@t+^if4asy!XWh+b zlPSas(FLVYcMcO$XcVBHn_}0p@aF(>jqNyU^c{@?w~n< zdXFJ??Eopvo#xyada`hWQcd?x&c5Z2yWIn0g~IvomP zovAW}C57%AZudCUDsqLej&v#n%(6yOSSvQle0~&7Y6YejuCZ$yupI-X$ZHu>yw!^J zGpCNB-&(O=?Fz@(g)xCl#PS*a;1Gb@BiAG2LRpMCbS%vZWjC3#$I)k@Y*=*lxaKlk zbUkowq-q>ZY0bKa@N^#1)z|WLpW^M;HH$hNd7F{912~WMbKDN#cKYG=0Jj@Bp3ff+ z8-Uvd9QQ%|$->`x;7$OSWkDh{%xx-aUU{yzuAw$zEG@d>hUP{jgD!Uf3f(}H;10}- za_FHj=wIqYdXuM9C(-FJ)>m(sj50!n$kB#b%m*gZur^RUS02|#9$=FTczp}fJ!HC) zr?-oIuCL_g>4xTXJx_;EQ~GS93vF1CIb#}G!!c_3K=ifYtaEqEt<4?eoi4u`^FDBU z@S8tea2tWEzm-otalt$By8-#aMr={sgEs&bKHIM4@WIat%bQIdBcaj(5m0GtW^{-^ zcXQ^@D8T4tbD()3;}3^rxKvd=hgL?gVPP9?w`-L$)T%Nyt7Q=V83E_gR74%xvSHTr z1uz;5-&RbZF10 zzGBxL)c$*1S6Dp+^Bj_0#hiwj20a35_AB&i6q*-VMf;;5fsCy*Cz|!LW(AQ zG5GZY*GIR%%Kdc7w?;d92m4ktTu5`p;SV2_MwHnAoCrh}j*GA8byUkGrf`wKt$4#O z_V7KpuE4q81V1&EaYvW|+=jR4pJ>+EIupOE-=gj@Y+&3L{BC$3F$XVyn@NgXePbm|2!YT3JcsMQ+xNzWF(sczcuLT`fFys zqdS*A>q{GT-CWHb;75B<&~~VO+Lw01*b2SGOoaj34=(rTlo7{K%x~<)w)gy4xi4Tu<5b5)(mPD@xIfsyG%G?JSXW&RD@Rob%9*QGFciGsd|`=GCsN z(6IwA@?3`k(o6wM(@FwZ1|*dXsmS_TbJ~jKr6HoseR`V;z20oIqCQd1?WVkVHZstS zZz{Unqp2#M)dto_@x&dJw4X&WH&1986?)UfiZ$l~SaLN6Vj~|23sv!+IzFW81XzG} zg6b1sn2vl(ZV$_F=TQ!ajw$34=^JUYNKd3aB7Hrb7wPeo)Pd8FqY)fB#!{h3XVE&5 z9z|}E9!@7j+DYMwoPG$UbLenTo=9I!NpGdaQe`6RZ+4|q)u%n$(YZu++dwUOX{seO z-(?98=x1pikh-i@epql&%&`L(m!?^?rTz3sTkW}vuPsV5*+Q0SG3S8qU-}A%wpOJ& zRVJ~E6jHVoAoHlQ899ZL?7Z}i)YOceNQDA?UF`LiNOGv_y) z538W7G&*tMV#SIT3u_9yvz`I1nl4_1iaKEb{b=@z-tDQjCmUyWr&DY%2z`%WJc+V; zF=s20(8kYgN_>;t5A@zdgL|_#%&tf1LT`3|AXey5{D7LWWM(y)U8`$Wr{KSuRUE>3 zi{e}FtKegu&BtGJ(Sbf}4UMGV|l6#X)4~AnvoerUM>C*bbHT2=zmoR~J&!7{VqJ;{3h$Z@PnxmS45JR9H11t%KlJ($ZU*{< zYDhOgu+yUkT)Ir@2fk&Zw!(LrWRqM?bDO4~R?XQZn!>x(M8ncqL~+`s8P>k-We8hE zBW8igpQ;gkE?uVdP2Vz6H$zUp+t6tM#Phek?ws#ux2Kq1=9Kt=X}Gt5j5ACFkoZpz!|e z=7>x*W2i0WDlG;|ZVOs*A634a(w;W;XSHU>3Yt9tDqYVN-T{*y05gQCR6WwWXJD1V zxn$7!0qi?`;?-TzdzO`JM{NuxukPJFTKtaWe!D_1u}Z~s|3Gf)6h)6-&B7JeK~!}$ zn=h@^J&Ae@WLlShiWHH^$$c7ap`DdGa z8-Tqh_dwP=g&c#~MAfVE_MterF7}Gs;ViX(ILBB=BMvI*$TdVuE zm|Da}14=C%+CodGQ1&%!fw^=l?Yf3d4wQ4F`a6&M^qk`d)Gm=duieLc?xZu< zv68m#b`>Ffy8ZlQOqy`AgK61#G_SBD*X8}RWjrgDvO$Q9PzV-MMdK&1SIzD>DCl|^ zsAD9JxSri*t4cx%9-SQiOR?%eb=M;>k&>+0eS z6Ou$|0^7@By%D2t$U!LaQ7$VqZI*GEi;uc?J7+S$^f%>Qi@^?{`WxBkc(<5W?%`8C zpX8uInq18|&QL}U>(Ewf0ln_fl@@*U%)ijCSC8u3&W{VbLH*x%A_O#jE zpUzK)=W={1x@RtZnR2FJ7=)+NMpHQTjtUfVbVQM5D#Cr4lSRo>nbEe^YO^LwKa1@e zNaIN=n2N!uq}5Yd_YS3e4m6`p0VFI?`$YH{Ic`;SU@AgN$uG4zP&5U4LrPikg__lQ zEYTD(8xAW@#D3CA?V+91*xYsnD&&i+fJ|8G7gp)Rv|W^S6Pp{6%iS0+snBlPeG_&T z9Xf^QV`bnr6Rs>7W|u~}96J7~apkixliBeFl^5`go2a^g4Kk(E*#dS&L|^W?n%TJ@ zrR3@Cqlm6H-O&Q=D5IbmtR^DCh84Y_7JYUX*X)_Wt}_>(v*~#)@UDqAT;=BBTTCZm zSHIfy!j}0r$o#2iRsI>9?rNDoLFPYsM&wWn-)WlMr_ssW9P z!A~~5s%8FI)qs;K|D;WKx6B`{8gN|Y|6tSiw9LOoHQ=boA7HIL#)E`r$+$+U1{_fg zj@tC5mifa~0}fIBwyQH}-7JQ$8kJGx|>4hvG$UkD^{?J5jDE& zWqh1SF;RTfoQo)T9%H7v$u$qoYawlzhxtppmv+pDj+MdM z(MN)Lw6j#PPbD{scMJ3@ezryNRD__%WPkLV))sl>=sH7tis8@U$9EL5gMrCn7X@+U ze0D|avj|zuqKvNpO8e$xMsSEIGHvYwOqRm*-TSCu0m4p^;pjo@7O=$D$86S0toDTG z=tesiu!mcJXS3qJvXI3SYx3@7uba&7jTCzqCK1=8wEHf&6@4+Eudcjn0%qz5wU{-0 zzH-KLXbW{NsENFrU1N%RNp_-ivlvPt8&?_?-NS};D9sb)7k4sM+%L-q^w%%&@|fNx z5pFr*C5_u?^&<9oU?ra@+`}k+F?-+ax}Gj9W=4n7{&K?Xgl!bnfc~|61%p<#S5n3j zKI6SZO-tC#QFFuwofXjqqB}W8+HW+wm~~{*y$xx0eI?z!t}l=4G$x&@V%APNVAnvZ zEMif;MUEQ_6_=E`wR9uwXtbD;Dn$%^y$CQh5nyhiNEf@Ry#qs(fNjMDsR?U(Ldg?I zkf5hCU2H%^e_xWQu2k(}SGMo#i{ATvb4l!fSxQ*%ekr~rQHPpITvO!qYPyPqBppdC z)nq>UMC+%amRl*Ph}}l*eq>3lGPY)tlt(-{UW8Fg0UV`$YY>Wyvf3m{U&}_T#MM-` zmPbZrZu^I*dM%%u#Ed+vrhYA(V2Upnsn3ok=sB3*ooG~wYy`H zGY!iRny@&aZ^PQN?Ax#}A1erZP=H~nUdO4EqzNoncNHM`ca zkIk|H*z{ia7@8(pqaCNl$5>jRi}S(xLe~v!RiMTbuEpfufIUc=SV-ZIBO%Dpq`b#H zWZEn`&vWtwgIP4<2{t&eP_*h%Du05lQ6hMadOXRsL*%rhtS8y3E<#eS=g@d(ezg80 z8t=@v=p)d{WG(~}Ep%8@xoMuQaFxK;YJ=fiw&pARJPGu z(Fe3;Biq_VJtH-Oc6_?21l^28?7v^+G^9!B5EjU zgRsb?c8`wJ`R5Rg$^r*z*=BYoUiRjl3ho`T!WL#y&!y+crt;^}L*du815|}Xu@Fva zuoRB|H@9EJtD8kyFU5*3kFV55!IftTz1eF9M`t~7nZOMb{z%_jHWzo`V@kPucebuT zl<@B|`a$0^YwpJ`L~yaJ$a$dxbNRmu)qd++Xu@)M1gk8w1{1=i%9MWXTPA9$*z1}v z=ALC-$y?M@d=1GSedR4Ada<_{l6F#)kee8@x%E@G$%^OyT7kF%?jRGsCex;yG9?fF za}Q%Fi8c3t$2C0q7Yjj1%vRb85x5B0KajdY!(L=<0)>hoj?I0MbyM1SippNZge(-y z^$=CP$od7kgyRdRrWaW!IdHWNqDfZgK3)a9%`zTyVRj=0zgGF}z1~x(n)aU-YQg5# zKS{D{&TlV0;QDs2c;FatIcLUwtXq&F14|^r8>UsTWIfNki>Vg(5BBS5TqgBPlfdteao!DKFr~7loSxbUrMuT zpKC5t%*8Na4SG};GhOKY1V7bMnpL{7xe%v|dIUZCLRNI_eH`ChqH)fre9P>82p#%N zmWleH0%0>7^zR-$;ah0U1L)BwQV*tn&I?!Q`ul>3wR9V0zwFhhPpJH5?xVSSxzAJm z%dA}+=@(v?RG)Z};rC9Q;yb_g$;NEs{HIB6p8wX}LA z_Qr%lJD#f9x030mE-vBAX9YM-!TD|V@Bn8-aDJFR3m!WRmKscX+@iHK!hk##_WbWtiU9 zria3R2rqClzk{Bw8q-=f#&I3(eh5>t3@Sn?=wX&NKysMMIUH@P|HfTme&~cY`9ae$ zmxP;+#%?>ytFO@Kx8w5)Z?8N`bmY>)huLVE>5Q~lv32Ur)UKxk53`9^2<}?8;2y0X z2Y0jL7K$}4?PFc7m_A+4yd;ut?WeLV@;(0H_-!t!5on@80qD zu2l5yMKEjPwuW6W6M7wvISM*c5rlEpkZgOct=%qdLD zagd7c#TJt^y>|((D|8CX7E^RO1ubQ_NY&R?(!!-|bYh+ejdS4!k}6iV#`YIyZt9|p z#RDPOIYs#7Q^K{K+{@VX5J99(s(2un4sXH*DD6`k zQOYI+3cTxDs$b5c=#5gA9$3hIk!uv4FU97*EH;elH(|3(dy$qc_mpuDAnYbQj6!>WWs`n(h8zv@2UXy8cD%Q!D2pbOQ&kb@#EJy+uh!4?(p0 zMSf8C7vE>E!2ee!_uHLQTbNTLC9hyTi$w(DzN&d3N|OBsLgQ;3F#CpUEADB;ktpM8 zxvAwhckUwX_mi-A8D(bYNM{TJ3t84y<7922AH#Tv{liiPWc(Q3(&{lW7~b zWxX$SDGpj4CvABR!(hgf>^kl!+|QzhN(Q%HhCzxSgM%#?h!q@q_YqZ|#DZ7`WZ>R} zsYfWH>nP>@h+z~%;m)DDA6d^UYDH+0rrMNui8ftF`%b}lWN$i=({1*g$zne$}}aX8k~+0*P)ps+C8Bpe{^ltbp8y&V<~etb^XO7 z7gs1{@r0uIVj(GH?A}Qme)WXc?)PZ-uQ;BQ{eKA){FwYmJrq;Q z7%U_UA;4Q;{9{PAdn0u{3#AamuBT}CSyU!QNBfeR&Z2vwP3~NZJqMc>3GD_dI)?yD zCa$CEbL{q^d7|S3_|RacwC0C}pr0jEa4XvsAjis5Cw0hSx{>}!Q2h@s{@I-OwVRa4?ZeWk_pSxxF^)QyW5J8we z%qs#nZ?yX?&HR&fi;*2gg{Cp6@D>t1au21=e?pn$Y}c0R{)9+G!reyb!f>Gr+CEIU zSMa*A8Xu+F00YN{k!-`;vJHnH6>SL72YTBe22dMFIe%fyM4eii7_)FajuRiX=w>gm z9J9x2s{dl6O@Xq7?J4MQj~e2Q-sHcr4A!`_*TN_pIf=4k6PNbG#yp0n0^5pno5r4t zaSE4Yqw>F5RPiR^hfZTw9fOtM7#a7kSr0cdM((F*aDZ5Gw?=$WpZJC7qJFF$?poo9 z1Nv-@Hqo=-vHZi6EagRwrM;!Gt3TCP%6DeTYwsF3%m7(#LX3a8jEd#Mj$gXqghz1x zP+U>E#w;7+YO8jn#;ENt91Q(~K8tSRc*^w;Yd=(u*WPBIuT0LfaUn*{@i^}e?-mxo z@5#|CZ6ildKS%XoR9wYX$Thg46`vp;{!?bw;wlPnQmI8aed#Dp2&XUU2hOcO{HkQA z2g@?0r+GA@x^RyQ^uFg22VC>(3T_v)`UI$a6Xds1D`qLxUWY+qkZM2o9i$1kba42H zEZ7Nq4Q^5J-{qXUear2A0~H^V<)&l5L00Hjt|Mlr+FiZ{C%ldd_e=G0;$R5sgEL|f zI%|Ci_rA*KR7Lnh3q7lS&zEq*E8zH*Y)UOc#=OgQ;T_*{dl3~*-6P96QO;rFGV|*K z@4=g%azRoVCv4uD97Vu#A+q{06jinQytM6jZQQmOEC(2h`WX zmY4V&O0lZ2r>~{BUy^Z6;uDft?aN$5US?~Bxi0c&CVB1c>S+W#+RIW3&ec5d!cd*& zX#`y_NqlYaBT9cyQQlUZIEbjiU9k35L>S>B)a^+LuVNcmcr4d5wCGhH&JDpTn^nA|85?i6uxA|vIl{0&>oM^^@q5Q{_6 z4lRkhP%$~J-%?=H5lr*NjIet5RvSND*TQekUlDvgOD(}Tn{HD3Y}2T)nzggZR=#Az z1}4dlrO^gtT#*Ki3Be6d-0}<3m+G-9fLTjU`z8c%fV#Vm5 zOkKC(F2XjhZ`($QMYi~zHXH$=CJ(4KIjIOly_*#QT^U7>GEi-RiTl7TnUh*{tO)3(TZ~8qdnw-I{jQKyBoJHBtI@geoqf zHf<<(J8vFOXkXI?o+EV#m&Ue3hoq*&(Shxr$U<7nJZOLR?wpXO#UWs+2jqY4)24uLLhd*5Pllabrb} z_BIQ8pfk(3qKlNfnBk@=+5d%2`Rx1<-5k)*G!E0IF6F6*a)>z%QwjDAgwkpEP}N(k z{Zt_c_csBlCE2`?4R@ezQRf2k6E-5E5tE-GnQLyDj_M_yMHB|f)w;rp-72{W@vJR` zFT+HcP^rDHW7J~@A_>uQ$IDRb?y@jGylzF9A^W<8X76B=dyA2*JujPDyI%xB(mrnH z_TkGJr;6uyV7o+mjIEUXwkP3uS-204yAKz%>TRs#1eN1?zgc~ncQq%79k&ZJY*W1FxE6th(!J>^)-(fvt z*6{hR^f{LLR5q4!+0ti5t)Yd;WFph~jBn=N@(LK3s(ugcdWUuEA~hi}-_i=3d7%iV zvbFrMZDC48k!rvmqS$v?`!1dMeWMT!cbaY&-l1r|$yT;fi%A1MLvPI?j@ai??z_yX zyu&uy%oB3hey6kVvYvy4DY!Q+O$&{XYpAjajA8S-PPXZnfB8`%3*3RsbHlg<6UVKz z%nffXInJalZrFg#Sueev;N?0lyq!b1@i`Rw9&0E1k`}@}-L2%?hj6_gVXEWX@;&)Erg---|`!$}Q_{dTYLbKqs+) z5UtZjvWy2~S#r;KmU>$}@)6mV1PDcz`NL_~`)p#OObmv721u=l!bM1EyTJ3==>wL= zN=4uUZ?6;qJ{o&*LtBjXQd;)`yRC~P9L=^r-8#Z#nc#tGkcui9`%bwPT3b9+AxKD&BM<}UdAss+r6~Aq#3!m~mJ>jR{ z6)G}FsEGT%W_C|*P*OEXcBO~Kv>@2IW^-SRL29igpm5r}+v8ST-DuBlD4mE?Trt$R z8>b?oYp!xi{ts)<%DLURJMy|PQ})M|=T!ci54zIm04n^CM{ch6RQ?}!^;pqyN4tNi zsuW1fzf@JyM~>Qmn&Pjlu{qwTKS6 z-w;!a=z83${q0SoaU=_hcorn#`~S&0~Sa2r?v<_L_Xu>9Jmd}${<3}p|J zL*@RA>OX@$iRR-bbol2UZF2n}q%57B``@SbvVGrE(dQUksegxB$kF{fHGa;nmI~zh z_0n?Gez~+9T}_m?$J;7g5Z}W-X7jlt)famE!lyHR&GhEJXq#x!7pz;cAavdVj~j-m zH%!cX`rbr%+%Tn|l}Z_Ks{jH^#w~-?r^2BS;UvnI&h;%DmC#()wZT_;TyHE*g8_*R zP`(MJbtBh*Sg@MrzM|AG5#5Dz-FM(H4=&0*VMzq~5ZzgP;NDJ%uofTnv z188?0mIcDSxF4j*y{wbC&!ne~mO(X~qVzp0DSNNSS!r@P5UmFZXN5W{^irpAR@{q9 zZY5N=mrcIWE!GeB2saz5TWqBuND}LZzw*QN@wT#7u(}c)y_s|p-P5Kcjt#766{;Pz z>fd8M`I&6drv5f7cKdk+f~R8vm3@uXq3~ah=cw^(xMZ1t9KP|mMmO%JegkO<-j4pX z`WsIf9G9N`2C@@5t`thz$D-n8Uq%R7S#^7}|I)Tn_C7cSQG@m{748F5q2jLD_#7Q_ zWMUS%_rVWI<)29>_OUd{RPQgDmPWPkVoy{0w;tod`-HjQqCHYE8e1wxHEsMB9TGVj z-hl9`jN=tL|1GK$IqvUUT?)IAPM*63ZsVo zhdOqj4 zZ=~eI*q)dA|0R_jh9{6_@;cQWhA5>Ys;3KwS;}ykQw8JXp+SF05NE-Tj0%3HAB^3N z)^2ep)263A4tI#;+y)VR>0BtK?Ww39$N0j6wY|zK;7Ar$9nQUidpv@#92@rT z;SpL(kAORsyXxWnM1X*=Zd#5YAvt_Xjw7sn40yu>g&|s(;gZO7e?&z`u&W>}AniVH zEG0AFqq-y5Rgi3Uh~O(uo!6IgZu6ITLpfRC4I2MF8_h%`9Fs0DR+m9LzlZQDg^_(t zjo)K|6Q0ET_6;Q+<<45fZ!c2TQJf^nL;<;vdIB@}f%8YXv*+?al#trMKJJnv%H(tD zAC1#r#l5>A1TD!h$p|hiIfvn-$$pHb@k>bPz-VM(0aK|0Fc(qbG1l*9k?EW-ZYo)8 zvxJ8e#_Il7%z#aa$HWHr{X8^s1W9H%DMdNFnKV*3FG>Hkq(59Qf}2zx++Y}G7{@65 zI5biuTpiaQ#`^?P=}uDiaqi@}K(wc6(Q$ZfIUmfS9mny4lgM%4-H#twX}s+A37?B2 zg{cP3aifI=wS@Z*XY`q)U7Fl*E_b1($}cE9|++s^UciB^lk09eSMk zbNA+V=09DSHFtMGh#7)nItjBr3wH?j=i=_rl;?A)Ko$t_D{uw{0&KdQSHRywZN7vc z=@FgzRB#$r9z?>yxO&pr6RaB(gtdRc9iZ^mwz4G?HiIxi61uyR<0SlsB>dfvaAONX zJGoBcrJ8^^dt6O7-5!JuY!L~3N9k7k0y9qYs;u_6CDO5zvV-jLrZOrIw7;PUUzhKb z>=7Cc5nu8fL#==HM;=3+?T3W-X4khuLeDR5sAEHuih^y&+EOt))|%`{4RX z_Tlg^vJcK0N#n#DES^3%PEvZfef>bKb#wFi2M&1iwRXPEcRb-+9#`_hzeX+G>{dF=#LWu|Zu7RJk)3;I5pSK1=a z-HyKk8cFUrdsxld7<+_nIz*cj?1S6<`rXBVD+3;)qu*Uz`r6V~bUwj8AzkMC-;}j=1B`1Qd`Yk`KD)S&$0A&y^oWFgrju5=HEXvi;mLz*8S-X}jYL6GSJAU)N9gi0QB(+9w@;V!j-RA)3wnIz z#nH(=$9(TURMpA8O;PNl*`4hNRb{&igCS-mUXk^jlgxy zINVqq(cQk*JPeD~?)H^t_cEG&g}p?&8OIX&$pv26l}X_}?1`p>l-z^cjd4GGXv2VS^kYODL>Rxd>|NZ^w?e zs2P{h-GKpXI>By|z!dM=d)uzxOO65ds6bh>i*g6pb!|Y#wU=68aTPi=6gvRcoFlckq?{ zXw5MD1hf0`n#N)FQFuXWFQt#LzuU=ZF0TEB=;wkwt}ab##=HKYgpu}|Zv5;)1~YJ2 zSfi|gG=h{;)S>9F(h)mH(1nq9)}DX=N0RU5K3m@@n#!-Sw=wmi%4_TcOzBiU&K^y_Tx0JS@sG`#4CTZktB^ZC zTp`NHvM-G|=ZkjlqCHtC*+ikE?e|2Tu<7q%KR6lchWin+;11d_+I~3VTMWDv0Uv^5 z;XJ;fvN0Hey|iNt+FM6?Q|*I=gsi0)td^wOe<*pZ{mQ6Mp-!!YDQeg@na4|E_9NOb76V^P*%P3h0$2J0)sF@H_vivZgd195Zf=9?ZK}$%PojIX?Q5>C@~zZW zjR2;}#$yf(mWAmZ@t$5vpsdyTk}s`$D~%rqA)Mgi8yoSAS44SSayUk98fTwtdK~W` zqYaPx<|6beyB1}Mc3o?qACFe!jK0iAjDib3yODF9{dv{xrQQaV3un57V#nKiw=ag# zMhS<*jaJ)gh7y>?d6w0=m`iwA+uDV`MIA+4xY6|GczgS(A|DA);1YJ;0SOys{dVd) z0m7Zbg&U9Ws6nhzR|*RKR@7?px(eS~Z}Cc8G}K)nB_4LYeO1In-#jgss;;-k^t-_q z?V5;S?-aw3v(%0OES-NKg*U8pyf2-0!`d4l$8}PLue|{(Ji<@Z3AEt```ieJA3Bl} za!}GiIXU)Qqf##+`ykqvV}B*0r?2Q-ooU@fNWI(tAoVUv>V|JoM}n04wUZ$A4wsO6 zdnxsJ+B^wTkCjr#ZGmQ~NBs{{xA}_39m=JCBRzbhy*vVI9%Tb!MDYJ(B=BCrM3 z674ckPA-HpT8i_9T!`}*U%9zHq_es9J0pJdMQiWSqRI9FdLw!@kitjXW2tVk{f4MR z|CTH4#xceILBuz{!ofy&!yG=O5u5vwfsjm3hTuQ)+*m3u%qyNFkDSp z`RLUnRG4qSB_4JGQuu}zK3LXpJ$D}MDWbssNJOz$W-jhK+(me$9@56=7cSvDoWj)Z zT00%Wp6^@m|M7M8aZy#x|L!h#7Z4Cwmjy*Y*?ZU51O?x{Tl5)ruao?ZuvM*_yr63uUEAnPp`~scEJ4`<`|UVXAAWG}nVBd!(>E4Tdr`w*QgBK(8 z)Hl)61wNeq4Ed$u!F6;B>rigRP9lUJhS)DlNL)*Q%`T5hp+Jconm0K3+6znTsT$h z7Gt;>ms9p)gl&Ck&SECp6gsdNvMuAX?He9>B{Cg$>1%4d3bK6?#+pP5)URrS-lk%f6 zQhtN#uJ`qH8W9YMpQ!O-U$IMNbDmP{%e&t9Kf87z6K!95Z<)`Nd|HTI$HlwH=uNH5 zd=uFd9Yr@_q9ksRQE0&ph`Ti|>+7iD2A@B{B?g!L6E)p{d3aS{WPFu)0zsckgR0v|NlvP$M!)|?4b|wA1ElHbll@esBb3-jx8hIMSFj@KT(Kpa{ULaJ zv!)g@7}S@v8-GUa22^sVP(uvl&tX2J+T9k0@G|)`Dp(FGpVIW@P~;CGXect8&->EY zL>rg;{Ctjp=&YhL|3PWoK;fDRV7iK1X1dzgtZ!sSDPz5Z-wvcINZJ%p1j)k zI4sWNbogf9&nd>`2+8dvu~8*mPOZ22?s8SIUeHUZ?pEJ~G4(9kmmlUwO9~$7i)Cko z9vE@WnEnJKOArudVpf3r8TibhFPfVvs2LAZ(i-1WDcTv)8jyq8xyDzGW=y`#H?VpL zdEgFeBZVQ^uu~q-iBzKXF09KY2#WH}|5Eep4mF<=Q*$js?Qh%ZusY;mKT(%FFj`l- zKF0#&45U!p?Y@D@gCNPircC|_kGN=ll ztCnGHHD;i*kwQkV+IpLkW*fWvLHhl?K`!ZK%=CD9+aeo8+X4?p+h%+u;N-vlh2C53 z^hD1+kEZmaVXZc_!8i)vwn7k>?-s;^_eP0J?}@u~C$*&D)vE=cobi5+>}xqJN<`wgbKXXqQUET9^=}OSlj@ z@jy30JdzwGuALkeVqgz_+yEh_aD36CFT$A*Fd=F=)cBBZZ=aWVf4G8d&N%>ZSwen| zru=XisBt4w?UEiIxd{`j6fGPTnf@FTSsz;ci0`r#9YJQB+>FgkZoR{O9`y~j*@ItF z*<+Y7J%wfsfS3k|<~QR?V(8itE{Yq?mgq4p`LBQre#X(KJl2lRRke8?xE(-TDB33w ziY`b6ml7jcD_>FXYcOif@cy1Sn7W z7kV(G7J5!JrI>~_@c|itMXM2FlMe{u!5^Z;rR=EKKjxSX4d78e(_eGzx zIR#g+9?gL1g2%v0YRILx9k^Xglb=PRtXufrXMMLh*|md%Uh+MyOkoSJZWmh=Y(q=6 zg|KkRlQLrT4qvwoN%aEeIiypTmD`DVnW2QPNRVe+hh>bfsNj8HMo#d|_N7BE77tqkc8JX0k}nyIw|AKpr1>}$CXE^yHSGqP z_rCAL6umzdTg@7fNuAV$zWA12Z}JUMT-40_Ldd6uvpFVz(fnCwEq>(j2bDl z)>NL$CV*Dht=j~we3BKmz88Wtmlbx&^SlAo>{_BE>_udYd`~P3k!M3}{#1Y% zrs$bWC}Jknb4A4F`&e90k7(odGocQjTj>Ojn9V)P)qyv+TElMC*vfEw7MDrzNEAr& zTVW!t0w!=M3S;=JFu|V%jQnd9M(=BZaRz>H)20u7YVvQ;y-cA4+AFl{LqzTRAzIdq zAmo1^`NrC{pQxo7A$-oqz5wQ^^FHUf@KCx@f4Cg|-^gaW>7kQ~OxppK<@{^I!XN(;jp?88C)T- zhZ2@4#Vy;qQ;;hJJH00MTo$wO@41q~PdK`2~eY{7!H&?h#n5Cib^BatrTD(Sn!TVHmC~YhAMx+0xEZfWehN5M{|=8@@iz zFGw*f)Jz37FurD2()! zXl`H*ee*rc)wz`U17;tCSiLYh8`>)_W(<3#M=RFf!TWf=UddPEQ+JaWn5-XsB{qY0 z<4<9Z&>5_437z?xZz@WZeXL5%l5htV3@Kat66Gya_M`96skn}V+1IwudJ{*(2`7OT zz}{<1`Fr=^#3wwARC%uqyNv^_utnbIP=zxip6U)_A%N4zCP;-o*&imad`fKYT;&(n(bI2UZ!x$J^R z&HlwV$W_OOP9M7U7hh@k!asda+j4>7b~=Axx3go_!Oon%JBZua#h$7{Dmd<&W~-!S z$07Vl)N&Nu7H}%N>G)A!migmzI(QsYdA=pdz}?-)d>$Hi!k1wiweFBF!>(6T-JnvB zSy{7L8Gnuz4A4mSm)@}3E?PHSPP(nZvG*w-)o&M&^BwygWQZYC~KsW|GJYIiC) z3J+;wR~&Ds5a8RQq2kAzlzq&XL(l!@^NJmBxUY@3_OfHXR3ULa9&Pqwy(-$|(p6nI zS$az}dG#SQxz=E zjr<1zZf#R|=0CoPww%&0xpJFI5?aBO#)atux48}V&nnoMvlAIHC6i{_l$$aFZ*h3G zZH5gP4yUc5gEnO-+b{&cq4ruEwf+r(jiE($#ZOO69h5-toItHR9-sp!d<*T`TAKMc z!fotm+xa*0lsgVG1Zb6yNe@dS|M2@z>)KK`$ILz$lu~NtLUv*;)y$GCw|jvPdtOJo9E!q-A?R8|adFCQQ4(0` z=J|A7QHy6rp_|ooRh-gCKt^il-Z%xDKUj%gMaSZlx#9<|=&O*y!a`cVyl|~p`_dkluydb6FO2qy4mi3gm>7MCER~@o>0bHzgU{Zur*|G&Whe->zRzyOS02+y~y%K|)061#FV6 zze}r9lxbN#qeTUxYPxc<;}T4E5KE1HAPFLX>s+2J>Wut| zOpRDw7GgpE60v4I6H)O`UE>4~SaHk+Y|f{S8}K~}^_dDXSY%2Rm-cgVk;!~1oP!yC zXnlr~n^hY9B;~>b|0Zgl{{=N=DBiiBSSxDAg{pgh>Ol3Ae_`@NE3U`DB<%+)?*5Nh zH5oG^?^$8Xx4}VwYlYqVe%JNLZ(DKepGN@tH7)xxeti$!Y@{^V)qobITC5r=4#$H-bt^`bg zkOiQOQO0#JJIj?#CcsK;LP=_;AOJq4Rc8U9kymkje%x{_9xg}TV|lu{&9@s(o~2wO z0JQ&Ds^Bh3#}2$%O1TNJ$O2HoxAGmwE#As%FRwzn&;&>}H_Dx$-DfM;x@ws**l}%m z&TM5ah8>s6?WBzyT0r-Hm!DKEGC*7Bgs>$P@=Zq)Go7`B0&JiJX0<7@S7wUZ?7-w9 zLEr?=;p-@!aO9a*oO*WV$SH7?Ss|9(jpEEUD~hmb79TO9qVf}bbOib6n9285M3GFK z;Hg#|&!3QPGF5PiUq`#nRj#e(1j;cU3Sw(*Yu!XEf##o~^@rVZw>ab=u%U=m9@z{= z60F~XPrw+*TfYS!hh&`AZ}MZ+Xu53u7#ngR+?2Ci|_p^*zvHY=bc+D!P0C$GxDF(ggCY z$jzx}akCY<9$AmB^d*>U#q}i9=JS;ggyF%pGAk}nE*U5c&sR88*cVp`Nmryw>=MGh z>=w$(Z#FICMhGmz3H?Ty6|gbFLLA7KmLmnU+y_sTV_JxlXlaEq-z5NA=$i_-Y>ACv z>|#ust4uIaKkJN&W3LP5!X$E3?E~617jXec#p-h0g~}8Y_07(xSb|@0p)%hDc(pTt z;i3Za1mEXDZxQg~+yV=BMZ<=WZyo@|4?OhT zNen;J(s}LmJzxQ7Bth5DVnMTKFiBQ^=$h z7r_=caMMxU82}d<#b2ykD*&{sEmah7n|cYBw-Ih}3ept<039isok&Rw6dVuWb@ifx z1bD4vONbU`h`mE& zf{Ug;&j5V1evz_g%o1k6<_|YV5z;3taf>z=^BAZAaZCrCKG{l z9yMO3jB;@T!Rgd`nev(I8c=hs>>F;nT)`t+yrIS~)Ov+-gSgSlD5A38hWgg6E={5Z zea0XUU!}-`2e#ynn5YQJV=E8GJMi#m3=jROwMuz%py-oX7^NpFrEYe&XPOl9TqXF=}~^`TsvezIxMlU5h99 zwUsr`?ZE%9x0#7buEVD8E}9eAYsG241-Im0@U*BX@GTMqT_DN3tw{B&U`96!oX9@J zptjC(i|n%Elm{W6M@^isOmod-T^-Zm!DcIx=ccHzb$fmzE(O}QBGKI~jwNV57sO<2 zU(mXn4HysYbcz25$8iV5l||2BxNdftMlU=lxNTlH;C~|Es^u{t(9I-(RG5SZ#F&O@ zZiw?E@jU|P)b`y-H#{~BIXWJ4oR2n3snPyhr;{68`zTA2|aZO!~0UF(W$SS4HkB)YJU z(W-{BY&Sh%2i=csvm%uvfY9><1DpQWbw$A!tT-MPOY{~v3hL=J#;REi_nZ}}`5{OH zmnbp`$f&3*1(R7)E!H?RKsp&F&bAl@i_xzLOQ^-*l;3wnYxVp82&5%1@+*})S%BbX zE0X7KoKHG#4l_&yx*TR~VJ)Vj=5=ULvZyD}Xc=YIQFHgO6{$Xi79|KI50DzV7@Cm> ztvKa%=psB8#v~U(2-Zp5kT%cmwKIqQ_pCu5;SO15I0A3+Ib|m)1n#v~)Vw-6G_^OO zOr{Mf-_W&Q1lD)J51RNg8)^|6bd8dAZiI0VDd}3Ka>z=dUdMgS`$W(lyoz+5E4jz~ z{U7u9-HxK=GREjyYV<0bTn3we=|^c!rZP9Tk$c5O2!nc5X3JM21nR*tBXPRh2UYd2LAN`t?^RI~$>bAg@{|aE~rMM~&IaGcHaJrym#eR{G=$cX}7R8Jl5Y zK5uE#96YtE%pU^Tx#j&LDmL>MtZAe$e;)Ls2UFnBQ-rR0J`Rt~QE&sI!5ck^>T;EF zV%>35Dp#Y+gi^j@-Sdr>CK@ESxMa(P3pn{cbgj>G_F2o3C zw^GEw$#XG4UDj`r3t&=kj42i_cs}S=$5}rH&I3V*^_z^zG<+2on^YWPlYrI>ez3ws zW=CNRc3Ixn9m;>=<|U@(qT$uS@2xHOd6$&a#S4AV;uz8!PJakHFaHR$R}4 zuDeNQ@lZ;Bb-RAmzYnfIu_6b*3B~1^{k0Zpgf`s_d}*z?`R%A;VTrTgPDm*Cqjp-t zQeE1Wj#Wd^KeH0^yaD9*+L3wRHzSzsQUWXnicz-m?U2A*R$S%Nu5slLftwbCT>lCr zu!D>%aeS~TUkSPzxd9wOb9~C&f!qM<-y#8(iAlU238+l>iljK!sLGa2Gor>&eufVC zlyRoPxDPwum_^HggiMR3?Ze45NY5*nvI(QPrZa%?5sg&aC`h$k0Q8|o z6%=%CkZ-gA)G_;kL+J&6STzn{Tx9{^hD>^iUiV{`#sT!p@})k}R&Wa1hcvRE@`3=+ zDnP-@6a>x85VIuQc#_l~lQ6-<*_J8_xDCTOkp9XVuc!iN)48Cq?7~v&H>*a2SIm zaOB=roO(nk8(uYWR5O&~yCE^#%oI40thUNUY*#)Tu{63xh^f?^eKaOQ2ud;@@l!GDwt#AFH{^m zHoiwIv#rR=-~XbnN3FQ!`yq|qR$P{yEr1FxjOw7NPV8m1n2PJ!mSv9>Ie46_RVP&p zv|4eS_e2Mu)|<8!w)gkXU5{S*2P=X4Pf>XXy_o-F*R2kGYsGEG!5Y1TUPKO5^XXqF z&Ut_J=A!Ijuw4y&Rpn%A8K%tjix6B!RNsAHj_gEK-<`>|^1!Ca+@Zm!!9l-F z3yP4W;-k*klpnu5)h*jRAf0CB!w%B3MarqBE7)KG(7C0LqwHb?`J95b)&d}LfWdUU zxZPK*?hK&4Px^3pJWfGhZUM;S20o3B4ObrM#qET#!~!6y*hbHeK%mb7kkN}@-UF>j zLn}ODs-XQtc_Wcy6%;O_x{;VSH1SCUyjokD6I<5=58u!?BbEMM4y~VW)|W;c0q0eH zqc8>HKeR-eJ_?>Jz`V}-?7wcSKp9)puOL5<_v zOe^lAdVZ|(ay2KfAXNip>qK5=?=Qr%ya$^4hIcE^s2M!i>x2^-Y{e=695v(M0257p z0XHZyIMqTn!2wnz79wxJ=>dim6pItNGAwW&tJM)#d?B ze{{ji?S#bGx%pql&e3*4oDO%&9U7qg(KQqDVTOx^+;;l{r`)jx<-d0vfI{qW%55zW z4PZ{WtpRY#6O@R!7y?_QR!zia6Fxt{G3C~YFep$Ltc`t2sU^x_VSM$M^5Y6UEc^?} z%X5vo9<%`PRFH9i4orfV5)RoD#M*pH#}Mo21VheIHnjC zX%!d98mgGA1Y8_i>k-~OS@{X;JiI7G4O5jsbulx2f%Cchh>gmRNU(hJIf&GIV9^14 z3Ykr>ck=GydMmBWFL(@tVl}Q%G~z=^a7CO}@LV%F9-S_5T7hyat!5hrpF@ixDra-W z?Zian3@c(eB39^3D)(VG(#C1XQ;HsVlFFtlQ_LTavZ)y!bzxxGv-b**RN+y9TvD#au;EfD$|8BZb-$zBvV7LgT|&YBG&KnwcMd`aY#5To!i_QhEE<-I)4vf0;wml@6}eK zk^i8;*#*Lt_?}>emBr*yFo4P9-nTmAMJ@-Pt@HPQm_(++!(x(*S>)dBR^kCMi{!+$ zNg@7j``(?M2}Kq}rC>~e^q%Sr!-imibrvti__6$=vtm`c8M8)XfR&N@zy4+X9k!~q z=W8f{InMPywDb&Rlo-JCf9sk+;3q4AW*l=hayxS$INbHP3Vh!I{}ZTfYAk-WsX%bw zRb4fIe+L2|f&p(V0TUk!)Cg`mS(3n49q_SvK;ov=lwh@~!JGE|iv;#`Ab^uwM)xil z0KPCuR*Mw)tOGtWI&EE`Ij?A)y5SycU$UE>VI4ZPB=WJ9Q2A?7LI$S4k4ZG=RP1TE z_e>>i8h0C!&pKt9gpqvLO3Cw5l#>1@R6=D+m7n3l%K&7tq1c{&<>x19oKS zJbgQqcHW>=+Rnh?YwWP$_CdQlKaQ;;Ek~?~3zWr_Z2+yh5nCTPfKf+D)rxA@22fFT z8XQILyT0^j9R#N}B0T#iRgxqdxMRo6nl z1VDOc3fPX`bgfeE6#(5#3JF3xjfZLMb;=r-!d>q8xUpmthVP7O6-ew%=5Fw0++&hYc|2X}5lp;W#lBZQC8q;UZO0ng-JjXp*^mnwK{tc*n7* ztClJ0YLIQ@j%_@4h;BG&h2J!ew@{57x5AcVBj(-%R@nKYIBZ|6Us~wae+xeLU#v?K zfd^>J32GfNFqi&Xp$xLk<9GMbeL>~9v^nT+iJf_&3citlHkGZ!Wn)Lmpn(Fz35>8q82f&m@b3`7VP2IP}EQ0y-lh#)|S zm4N0G)IMAd3FKRGjBLThSvP}=Y%3nN&vVKB?`CjOz_&Lb=IO{q0CS{RnHnjA3-%Oq zEEjr$pmyUe;3CnABiR`jmF$A3SQO(=fwJ({HU^|KIx`SF-htR*#z0BhA03GOyzVxr z!GJZW9_k#+vi6-2!c%J?gdePEQVY-~h~{gXd9-eia*Cl7d4u;Deon!^P-rcdC}LG8`DKI$WqaVJhQSHB#eR2G z7U0XKjRJh=oyxVgt7-F{IK3kn{)yu26~A)16<#u54{3XfTmt|4*`ysSEF8k| zjIaN_q0$o}b_%M6Bh8?OV}%(RtPR0=&?T%Tp$(iV2^Ub+Dwe% zhhXtALabo%bb>8hexI_dn@i)P=US>eb4WR@eoPse%fCof zZs)f+fSG5jJh-FGoiSV@s9&hI_Ox)zV@e4-tgOeW3Qc)hNw4nic9u!(teZOs73PN{ znHuW%^Mjx9awa=x5t8R~IDXD8m6zXZ9t{1r^1FF?CNqF_h&7FLPRCi?&FyT6smsYN zDpAYRiuV$k_n3tbsh-oxmXqML69tVR-j_0BXmEb+FzbU+EnxMTu+4yFuhqx4&A6Q^ z8d2Q|x3j7P8EK7KT^y>Dz2%=nj503R!$x!q3H@fXI>ZsUT3s^iCToAVoh+qosct2; zG%EXDWw}hQL+PDou*bfN%^{2>bnF@IMCK*hAR7B$r^Q~t^dVN5&lCPizgZt z#mhU_z;=mLbQFe~=6AYlqYA%#%XQ%2#kU z7sL2UZkx@<;vcuOmU{u(k3I?pQw5F_j~(RMqBzE7|Be%h7dWM;ryvHWT3;B8Bq}I& zF`%~Z-kLsWQq5XX=E0%qiVkJlZ|}h1-zI~2TO+nIqq2=AYZRw9E4V)ngQO$Dn?+?2 zl+{UXNP-c^YUU3`x$F`Z)dH>}Mta(LRPdp4hD&0jMQfn!A7Dy1eW>&tRX{CFyjs2& zqIAofvJlp~+_g9+UB<;eUwjXGLUNfL{jOJ1>eQ0H)bk@H+4g(5-$%-OHhazZ@Uf4T zPaO$UOroz*>u-ea8Zn!ALzw@=owgzz*V(uWI>k&fQPD7yn^7cG3lmL*}RcH zn)A7`&~Aii=jTdayRn}ddaHOh%?6I~22=bO%0#`yow2)Xzq+y)yODIQT+D%O}{Tp5aum8`G@q zbmwkmMozGvpL}r1>lsK0eI0V)2x%VA;J-(4dz1@v{VW>7Pqi+-^}|{n7DY^$9C9+MfvD0`iZPOghREwBRLJDmch84xE3Hg{AY{uvMoyqahn|nyMrs| zoj6y`PiE_paMRaHn(bsR8wn;Erc(q`$fyI7=^^hdEpmlacanSMtUulHlD+c611WCr z2+6w(IvXGVV>s^{S74`u&|JP7|$x-vZPN2St^=ws(k%CM}8VKN@S!QJ#1OW^db zQIc2(4qQMzenvha{jgb}_Sm99Djr!FbQ)HuigOJ{!q3&v+}lv%lHQpiFe~DDyjnSjyB413BFoQ_{lA zaC6V!$^iTJFV}78pGkv`E5q&B@qO^c;=wKf@CoI;RNTk4PhxiBV=|5-VTMb#TaGIy z*&Xjw>IwE6H(#HCWnts$1m-iJ)(%Ufs=t-~z@*lC`OE|wQ`TDqgimR?gtkK5Hf)w7th;ggs~t_pLwjj+q{!d5Lgt3&xY zygWy?vr+dD8VDww0#-SbIk+e-eHMq!#ArigCt#&GzSiUno)JRy>XuW?@SBe!?HTG3 zr(TLPYKU@2RO7`qfFzVzgIvz0KADqFk<&%h^QUoGW-3K_sac*P%FCyAD4)d35uCac zs?Y>2nZr4YPl*P(iLhUsm@$DgS@l+zFmuW7AZU*gMe%q}3!9}N3YVZ$uDN3)R1T+& z<#0XaI5z@0r1E92jJ|dTuVcQ{637eqQ5-&Aj^l80dT?F4(-iROvC!gMisJ2k#m zIA8pTtfI1XRp}M?KpeMI&PWgwpSTc9`0{ED_$g96l+aCGo^GswIr{HDyL^mV`HC_Q z?Y&)?MZI4yjCaBBLD8?lTo_z^)=f>ZEupg43$bsL5BUbFdcDxoO+YP%%461?q-NOV zD$)WK&_Rf?8*iAQLRAx~#m!{%CmC)C?^ z?F@*vUC$*@!R5Yyw!PCPC+QHEfRK~+QWVO--M2l|VYYGMZ+fUdIb1DyOsYnBSEgEO z>+7iU?qlZN@gMInK3h0P{4S~T9%A217L(Rf?bFNPX7MTR=rBy(P7GDf5MH*+%kp_? z;2Nk#Y7keBJj~?hJQg;3s;A4gC&Q_E>NQT=>9k6PQK)Di$aTzK8U6Smkr30=Gs9Uv zw?nzg%UR6B%lCII_wn*nIUAD2O{|QD=K^lWm@(mX=zTd%4j#jmX}n*(p&Ev+K?F@4 zK+56(iLgeTz>ygp%DuciU4}B$v5}u*!c7;`;r5Dpm=&2*VZEDx+d4&9lQy_&DV+l* z!AkQAgD`(pu?(g1@}4r*iF8(>%iH`JS{7Ns+{TfFyK(xdKe-I18%RAH{nfcHgHM}hQ|n*-vq*V*keALLpiU4l z`i0amKwWJj6j8xIRS^hUDa{!OCm@G+4pjTvG9p7ov>X`5tK*7mWUm{n&awsQ?7?cj zrvzPxhE}l<8|ORu=))4jV7xA^G56`%>cn)V0L92-7PWyy*kMD+mq$zkMR+wU3ST|?AdTh^DN+&Ed3%X`h= z1f26PKt^4z~Tq!s61xaV{}vx>MbrA-K$LnA*z}=&rCf zOuY*?hO#ce8emJYx{u#j5ATb`ghp-)XVAyP)zj0ib<1X=T6~^PMI+R41G!FU4~5{Z z+f(&CL<#(dk6W2N0>j5~Dcw6l9br3#J|3ao?wKfpjz9@N^IyhHi#9*JbR_S-i%q#L zh!)~WvBpvAdH$N-%y8W3b#nuf;uXJd5PwT<^d4g6HAm@IO`SkXMyuZzHiC~tw-X6> zE;4B^*UwC*=e8t5*CV0uR809Ex^;~D3SMWKK2|+58S|0~Je9-v(~a=vvFeL(^SUozJS3F-F0bD8GhP`#*c& zBUbN>6c2WYqGF9zjLY~@@h9QWOVn>LnRzg51X%4GMeXv#ymnz?`_eb17!`~yS=K4_ z6m?29euSLLZP6$NL5ip|#~i9i+p&m7PiLJHau%=R0bE;Ni^CedIBcq%3e%7(;5>k9 zibggZP7`*GMM-i6Xllum1#o$d+u70qSkEvSfbq&>3?vFzd4(ku5)8O0Z?fv0k94Qr zfsB;K$*?F15j2mIShqTlT+fWMB}(F?q!bQsN0h|iWEs&^oiK%>Jc;g|40Cc3#ZQ6z zSj^o6VoE-WIfO283X+^EDD1zY-Gzwqzs>R_QC^HIOD*`vd3lZ;?@nM+(sAaPaZ-F~ zG+u2^+{1= zq?7hx{#e>|x_V_|;1KInyhDGOW|pb@U5&k&O1nurLp@=VJwRh?28;^dFhf1t?$Wrm zc$Rk0R4;R*u`p-1L&I@;g%84Fnp3V$G3$AT^41T|#-&T@RzX)gJG|m7wZulhoU2Y_ z@0^XDqpE$iFEBT=Ro*10IPlOJ23^*cV1)g}1!SD4pH|FKi(UMO(Llx=HRBv@FD7-p z_Vti|$AN}kl@J+-VESR}CAKa|kJOB|^>U0}-fQ2A0Y~s1$!94u#6-#IX!kf!sbkD? z`@ZZaeuwq65#Ld1oJs}fsi)8zv(z)~2*I<@R{f(6n+&F!4E7fc>TQ<~r$9$iLUFc1 zOi!=~@gmokgupghcD9OZ{%Wc5Yy@~X)xGmxxAa8Lvg{c1yjNMso@;;YP;4zndgFuI?hB2O+HsW$0_x~Voxj8%~E^O_H)%i zbj^9{9p+1Lco^Y)xJ3A;)v71_^7-mSdo@-E%Gy)w-a~oJs;~FXXTv%GK{vFU08zGm zo%f+!1~bMRO2Oal_jtFb;jg2}o6kbbn!m)~?Z?gEe+u}L(d~E~fBO`-&2}`uh|c#00`^y@fYnZfJ}yGEvequ(tCdYk8<$P;TGmKF2v;pe$R+ASz4%MoJr*%Z#`9*1VM_86>@bsT|M;@jLJ3geQd8&s=7s1zRNE5>rImi~)FkD}# zz1Y7;58+yk``zfdwyYGz%~$`iy(wNry!ImXt?ulZ3N!4f;?dAKH1lfp%(OSHpY@sa z{MG7&lgjw~;&Et4G#V;LUpXVM!9XCYLNp}koEnl->56zf9J%LKC6BE=VJ7`b2da~4 z={2bA1?y*RBJIAWtulRm=gNZrwN|E&iLI>roDlMW-XMe{%LggY2kT3Gmx@quHl*bv ze=`bhriMBf+74`w!>u~(ap2{E!;F=4EN>3Mu5tH~DnYo$1=O@uJ#9wt29xe@?E^>9 zJ=}rrwtu1fUcOKW$0>vmzd9{uN^(8`sY^2fdkoDcA*$X6K3zuLXuGL>=e-~&($)(j|z19in+ z3}fuQPW7gjHW4S~{K~r$;I22`Ck@{bDnikSV*I(6u9ZA~;;XlBw`e!PO|p?)UoM7TwGF*s8hPN#x* zz#q6Gy%cv^pYSD7)%9xM6z%596dAKp?xc~OxLzHQV$?>zVXx5n?4*29;gX? z9P>>p27~zaP0Tl`2n>E(6F406%@_&>zo`ktVfm%4ae5&b#J3*&TeaEZ0&w_sO~4le zC=CIJ_*NA2%@_;@TWSK6V!r8vz~GmVV9YmdAQ;5Ac`@Il0bp=9BpCC}sO|?2KZgio zKI(pOh;MhseA84gxCAw(GS&B%ck+Z;tU8yWu{k>#pnDfjK$aT#Z67DaAU^ISSt;4|ppjp_(YE87BN zjoVH<^pKO@F0&(`RcVWF#9M;S0B&NUveXt46}x{D9zM;sexLjVoF-Y zES7P+Qi_Xn-wf5~lQ(Ir08T}3w+$A&%6#@TI4%yLd1%!%q#8IjOKiodedyigYO-C< zrMmU1pBy)-(`+92=m<#rk|a7J4)KbmiXC&2>cr1pt~pm#Q>$I?yJ z96%n>0pKhS!1GP1tU{cjWEF1mxSg%B6`slAoU$p5`W_w1&*0@e-^3<=$Tx91vK!G6 zcTMr4m$cJq*$VZ>zO{Kc(_)9G;CJH+Pl>39n^ozo${aa~3cfw5XClVG`1TTMLG_{m z(o8lB5skoR3a&K942uco-}E!6DX0$U8}txkq*ivbzwVWCW(YUV!l&YLeWsyW1~nZj z@VH7D(2gWJc&MPiOR$bZ)`tuFR5#~w*9_+sN5i@EVkc&B3Rky>h6iRp=6 zM-4xXH21?`ds~lH>HxL$APb_=AoR%tabATn8~ixLkIKOna(^m)Nn?)`^cllDM5_fO zaqyEeTry5CGlam8qIHo2qIHp@yY0M<;#K?)&tUwQkuz|-h zDh}(!d;bvBJlJs31VP7AD|uIxu}n|LvYNNO53z{39_roE*8LZT7>m#BN#nImDinmbez+t?b*? zoS}g^P<9*D<|6E>4Yt9Hj{bn>C*1Oq8)EQQQC(@FhhA_Nrj96vz6WLE!$p-q!8y1s zltfU6VC@4t%Rjs2txiy|nM$xM*Qa*HY73wQst1J9FFEFmc3trW-Qaj<;WbEeHtL zt*@rCI~ai#T@a`dyNu4{VTjJ|r0?%SzhT4H6h6;$<#C-YBmE+Elw16mju{P}++zjW zG-?eh#jX;DUvn9y-U&NaI+3uq(i0wcr+P-59TpYw!SID!;kg>x2PNe(cdsRI@6ng+5*`u0OU0Q|`- z%$AXR)meqIsIVTh$EpsDw~HZ7I&i;wl3o9jGB@D2 zkxSYJ_B%{f8`Pe5=@q(lgL;Om$-!8EEBws{^+7BENurkz$XaZ~5I+KJxy94~)0zR-_z(?-w0Dl&&zFht(HV zM((sY_lFqF_UpWr!gEsDr2akW{)bc-Wj&;N?9!i9@Q`|QiuNlvGu$EJnzNk`sSmgq zxo+}`aMeb&o6U0-9~UrueCgX@0yH*->o%#1xmg!iGH-hr>pfy9oq z%e5kEyr*EWxrMhdyzDV`jYIr0j#BEAs#&BTCan=`>9e0yedc!F*6_g%1%qw$%v0(y z6XRWKe7dbNJnFl;p6I8)_WmmU)sh$1u4YUm#Azi3UJlRsuR7joFP$rnaizVW zzG>GUpxrO1Lx%>>Z#S|MpA?HlnK(Jg>p@fHW&~EI5fz4yOJ*q{T(odw=#GVNq0MWAwXm z1J(jwAel?^ix4x}6`Vvp9Q^a%at6;1qiZZlo(03gsp`;mD*SCA1m+NpP)f?T?X+|x8u1Hy_AmCl6!Pv7Ri;1QR{tlTU-MjTDz+1;rOw*#Yo06pmEzx3@3u$Q z(Z+Yx9d>CTEqYJQ5_`_{@pS8ZY$piIV@jjLAHRnHL6v_MS|lIh2BD10{5rPx4H}2X z`*=@}WLwvB=#CFmx2wJncH;%kqRk(umzacQ%KlI-Gzr^j=7;L|#7K*|SfJ9qAF4Oo zU7umgyZRqj?+ov+&?MW0N=Kp1+@C3Bdow`QS-X**{~T*^fd}Z|=MboT9~FE7K?c{; z(l6B0>;v6@uqx8FfAkMVAG!X=*eusOoa^Z8q(U*C z+mY?{Xk9TTM^Ixs*CKE{)~%@op%qs}H*Slxf%luPTnw zN2k)DJ?cprOU4WSA}52s$)B{1s`jW^?mXTh(<+@Zj?6G70#}o9ZE+83+@q%V4UA)$ z2o^?j3M&Jkz=DOv2>yA`tq*^*hiwQ64i;4eheW$s+d$cSp`WP?Qk%7I4|dhOxL3VY zd@vGdPzy$l$Dl!p0nE@_)Mc(+d5GdB&!@(1MOp5LnMD}>C?DumoXt&?_Z8fm5aMZM ze5dvaU-p%{)s`4JLVc614+ZN|8d+3vg9o}Q089(_0 zO4_epnl*Qevr*e}q#2JAMC_sFO%5+#7IeNDuG_C3vSn$*T&#RQ%A0vPp&ZlDNAU!Y z+A~q!Ok8^UtS~rP7nc~UG(RNcb@+b8y|@BIRcl`nx4Na7IA#dYGk){6eX}sm0wH(?jLeoZ(~{ zqxv_vHG?sXBaV58aHxd;FwP2(J*1AZxt3rA-hx%DWrtN<_`?HV99TLGdmAy<9Z}Vk zz`3EDJ?$JxcZ7t+;K_ov#kr*@TN>k6CW z*%kK6%#E1mtiXyI@1(Ej^*=Fsj4Ry1nKm>o9TP&k=}IrB_`k51LbUwl@V39yDK?Yg z7bxij_U{TIV3WiNSgYWrBGl3@B;ViIVIkUiS2*<_HDD8+s(I??_yfF|!N`l0{c=&? z`nUY^?2g-UJD|U9^Mr$Y{Fgo-F`P!({XNGWaLcRR;0;+z>{DuF;*;j_m;whk+)zBs z_xjb0O6chry}BnE+*ABXkY!CIuz~9A{-Fu-;4Q^3LA?XC_pOOfl6Gl{OgA|EBYSa= zZQO_fErpWV3^36QB(zFua`*?IDb#BRd)pNA;W#mK3#L*tH-_mUxy~U5gcb-TBF)dM zH*oiKqU7$iP}-NC_-!ajlHAD%2xW|{n*(@(JI;^Ca^jd86w=Z-|K~%Y8z6`|#Xp?z z%Ag%#C*~B$Jmzuz#>5>QGVWU0-bCXE(zi?;N3Y8MOm7}*v39+qIH4aBt<$}zre;*+ z8ETdNrzJ+FaEdoa-lEA)|GVNIXd^S6?eaILYI>Bdnh$=elPTHC1 zf6%Ti2rug9e=)9a?nK zw}OzSjGKqy2zmW54{zaitRaQ&BfI{oc~PD>ED7d;(Mv!I_EvSsTTV`E7|rnyxy;Q9 zoH)se)Tdbq-a9kzSxKP641eAb&~c0nJTXGH*+ShssqXr2_AR$Ofinu=RSq0x0^;Zm zjIQ1{tY`RfWU(CMHW-*j4PJk5FXs;&RY^6yoa`B`9H|#Rcc>x#ZN^_Pfo(QKCr{Csu1k#rN*BA&s^fi z2UOR~KQuA;E8l<+AH0s<>4p9mg$6Zb`#s_ZuFu|Pnx6p6_>^ZH4ry{ z`!np3Kf(>FKgD*AaQvm=%5H-sAo`%gn^sF7Mv@?SYazDA5vtd7<3ibH(J*b)3K0avnI*`a(bFULLj z?%>UF#9)Gv3I=21-%k2OKOO|(#BQO(L;Tme%DDHerK<}31MHHA8VWG*bOxbcNqQkZ zYH_r=(Eo#7KN4O))IZT?$C)%X`e-`9k>Yk^a}vY>Bc*`{%lY zm-gZ|pH?M~&b)3Jq ztAGb$uTaHD2)ruBVdMoy(b94L;VC;l+>)}Dn`(FW;Kj6Uoc}A)C0YY*9Phu{Zmg&5 zll|C=IM7kN+Kp(TM`h;YuwkpQ4V3ridYXAMY?$PC2hU;MfwVVlSRJ2zD0Jt^{s)Ig zrkgnzjfo!fyF00#jqtz%M7Y>}%|^6z6Z02XKg4+(CQD-+K}B~`(FA|3T^qvG^s-s= znJxyVw(BB?)Gun+RZ%{?L%E21+H{q{1mz;$@dE!sp{wG@`D9Flt`=}r!!k_?Q_BOi zs06wy7z;36Rm3Hy`ln1`_lqBRbQoHDh-Q`gPq*vOwrlPt8(lNmpCV{VGTl1aKVX24 za}_b_%jKorVNqZHOX#k+<8`m9v3VB-HhiAzWwyToc8|(PkmUK%@El3GqA9 z_WN;am;&A-aRcETE&7xL&;RH7?k@VPgSJKJ{Wn^&lC%hlAd|yeb z_`4nH^R}{@N5!|AWbxP0o0@hPWx3oO5wCooR@xJR5s;VDtxf&==d$JnBMshl&{|jN z{mczQc5P$vZfZQ$-?v(RK$O>_ydb7rTgNg9ZZnHOoL2EYZmj;cefNq6zszq85Ov*e z)^#u68{b}+zP1hLVz__D7N?WI6LM(xx_h};u#Y89EN#M{^Nl3leGdG8dj)AX^y_^A zC}TX{Pn&iz-%}-O*l`#C8(#{J5JAV=*q!wVTJ3GEdjmD{44k#b(tF(abzfjq(}_y<-ZrNfPlDjvpvXeqI+p<31w=i*N5v_d*hQse3VjM26K zR{prauf6hL@E=`Q=0C%wvWax)co*AviTTQn z?(RA!@*^g`?5benM7t#1bcVmX&Gsd=%K5{ZH7Qr03t?q9A+3w`sMy9|Ht0D$460QedFEJ(=(HMU`U3Lgan!}lMIXllN%Vc zF$`W-F(@e4HEcle4lB6o>ZZregu8|vlJaii1O!11CSgEfcMt|IiyBsNy{`Bm;<~6| z6|Y==->T}|6nEd}_df6Qd*0vk{4t-N?y5R<>QvRKQ|FvI#c3(O%4v!FAKtpzd3pYP zI}`@?`a;2Xa2*`Ao9DuxasgLR#`a;^!MPyH(d2kiaf`Fy0^uzvAYjw5(!u>MeD1Iv zr~kD-V_m~C)qE{Z?JrQwYZqWwHlI6q3s;BYsP7@w5NJcmj$53US?d^AK(v8{&f>Ac zypU|h9zRu3%+0gx@>&>mAb~RCX#*txfSf9myjby$m!xxR9D1R7AO{AwF>RsqYVl0u zt%c4aoG(Un3r)R}4EVM4V^i!la`M+0N=bK;fwwxxTU9n5D@f(7P6U-?gCoCTF?1jd zujsqPwb=P*n)~EpXM;)GMb<8Hj?2lV8KWERwa`5T;dz`k9XiT3oC0A0;z{Qc=V}f? zdy3TDhN0$VEd%Si4fRy8;ujF@H_jzKR*}#^;oQ>sI`+-jp5i=Sh?xxN%#2=zyB$yC zNQ*%%ObOTR&R0x`qV?77&PPpJfULd4d6h{xL+;YBSyq2TO7Fy!6uu?1?sQHv#WKm} zJDo3>q94QGna;|OBKQB+`HpBp{J6z;(?Pd~JbX9USqq)J>R-u4zjOXFz5WP+2nVHl zIwm_VrDfYeLU#Plxz~j5s;QW3SFltUVYQ7JFR%y+z(wcYjJ9wja)9OK3CP(}> z;<|_7Fq@cbC=N3@4vh?lCFHFdio;z74o@*08W|2Aa%s@{h*i&`OYIf#Jppw!#@8+- zm)1JRn#zlax4C>EX{-ebyFH{6A1#ubuA!u2nR6H^Tk4GCQE?cM-98#8XEleY7mx+Z z&_ygo&n0!w`$~zr+_{loJRJQk>7*}5peRq0Q%U0rXGz>_zN{Z9iyT^kL1I$N$?dD1 z^Eg(~KaXd6A?(jQ$dKM-JVK{wat)MXw}>00+|-%^gMfw`;z$ zpU4ub;^j-2GAmc0U9>5(Z;kUFk%s@N2sxn!Wej>@L~BB~o3u&9)!@uefpa9}{3+ZW zJ9-tVY@jR@KAsKE&rL!zZwSql70%*#e~{Eu0VQu9ZOIyw)l1RPZs5&fwFp1Z z=1erxFT*PDIYB-}&1k71S7-k@#B7s;YV=X8^hOdB$r zR%yNvE9tJZ;a zcG4tmD(P4UWdIA36kSU?*Ez?g3)?_v8-`Up6f#|Qs(D0R?<~sfWK~`d;`IwHr=mGB zux|qV_SQQy&SzlN$`BSbX=_b9EO&>f84-Gu#|eGb`kO=4{I0Pb*8tRl`y;4|k^!DU zK3VTvQj$hDok45}0x-Zf!H^3d954L#3gLqj#705(zsrFI>i_^saS9A8Dz)ruIj zl}xF9J9%%TGsDMTwBOOp_Bdn$)2jMCf?4oPceC$wWl7ZFrUPls9Gpd5Pde9|qBoI_ zC!KdYH~^TbANxBm6vZ_y9~>joHbdbWs~~lou?R-5Ceh8#UsH>0;ZxW+;=o|#Q_d_> zH@(C`e!Izeg|d*20%0a>uV&~7SQl3HZ-)p{W9Cd+{Uzz#MCFT@h&MwSkV>(^&?@44 zGHn6z4lOSwZBIeXsQbvtr=62Y>}lr^NgZJ)O^1f3lQT~{Z;*sx{4JtC<17%}7@nb; zSUUue;SlF=7u_04G8e=-7e*UmTZvB6LRTYUK6$GJOVoG7yTw_QG7oad*x2tGMH2lX zvUm%2!EEm*%pp^rb=GGt97KEXa%v{TW{>g++y&Yi|X`UeUiG$vTmoFwK+nht=vHNCy z6#Wx%wPV}`pClKxJ8_ngVe=bud%JVIy@C#OVJeItHl7;`=e~AlLA?4rC$#)n!&a!| z;80b#l}a^jWbRgHkoSIcJ=oqC)RW7oXAC0HQ_67|M{0&>-M=MZrTxqZ8Hcycf$WJ^Bj z$is+Cj@ilP?O3!}J&?;5KIgnf#Hp?4oWs-P??bCzJI(T${HJ|)&lY{br^)M)f|=yn z=bcqXnU^CS&!bBQYnLj*BA6XTph$fH1Zb9^`HM12&2QN0JV!i-cy~H~Pvwd|JDu+A zk<20Hw?!hIWzyK-%b|EU#sDpQLJUUJKRAD9657eCKR9y`8fEhzoOf3X%)sI%&*j3T zw4#GeI_kPzhe^lMw0!!VO~kcb-(ZrWc`=Labb{U=!wmpz!TEz7YzwRl?1FLrR!p7& zR21Z}qQkn%u`<95JjM@Y;vby{4NQ`FPBpEo*27xfX9gw+r^SRldlwX1`{7lwPmS+! z91Cq@Uo6x|afaqoe8V&bQ}r^Y`Z=>`F?a&*4~!QYc0qnjrDH?*jNE>xAeSuO`PJkz8;GDAEFe!!^xVi-HAc>Erdu*)iSdQb_9g>TZ;-iQw(#=`((-s&U-D|Ey#D0 zXm90>AOm(gFBjkBc7qGiUnMUt{E6KF&I6&P7i!FIKyKXQOh6R9%I)Wlu#t73evSVY z(s{FcWD2s`txI>1-(cD;o&PWyaf^G5139ol%nzYI?Qme=eWG4RN@LD9X)ycLz0Seu z(Fm9t1{dzDpi2yI%+|<+z0P_BEMtP^C6PlfI{yY28@d|8o2BDr=fpwkN$^-4${v75 z8swc_f*CY;|#6ggKQAu=66B|W3AuEG>Vn9E3~&G+ADPDLD5|X{D?W0reosc;R-cg{7DfT%zxeuC9u9@5r`RG;W43jAeC#nu` z7J5ve^3TritaVI)|3w69RfzM4Sfyo=hYvWff(-k7Uq$oWKj8@Mre(Jx8!+s<3X8_2+Su=|^6Ze6uQpk`3}y}>L}`3^WR zt4aNHM17Y@szW1L?>o1ctQC|O3qvCZK5&kMh(uYPb{|PS?72!jP39l=I4!5oKr}s0 z9{x8hs{j`LH|L;9^@Ev>Rre3HCs(qH(6^Zm3+P};&!SJbTMl6Fw%alxl!$g~C6x$p zL~}AE1h`$6&B1{i+WP40#C6y?eDKskjwjQ_Nb9P#+yLu71hDdJNXua-TtMIEE}&gF$;UZP6WP;lvwY5RN`IGmCt4Bnz}w3O zl;g9REZmeofE+6u5npV@DU~fIhRi*(lLPNC8Z5gw@M88vgTLay-*l163(M229NM}b zXjfR{dY}c5a%c;?$oGk(81u!#$p&bLIkffrII8fD`zflAlCM5;jvj8=11+M3llVg@ zR`((ws+j{LPs`P91el zv-90Bn0^hk36x>sQi}zjKspc*sq_ zwY-5CcHHWxRBZX0EdJDqn@`x>w~)?HA(yl;;r>gK_;+kP`1TR|&A&T`50`&o;6JGc z|L99hVK4iC&GFZ2$-{qlF1KO>i1|IAj5r2HrBZ5W*OQ84w9Pj`hUqzynJOI*orDqt?K65^25}qS!C$&cYj*53|XToTxKG-cH zwqy9n^7TJTzn`U33y-|qOlY293}IFvBJ%PLTfd+N>F5I-er$Gkd4_~=XJ7a+7Tt&M zj94Gu{!{qD3mJS~{vM_sALuSNx6~7GrNW*hm`k*OI0t#^hjKvvEXMaK&|ol!14_?j zh}dckK)2hi8!eUpWgd z!wFSv6nXP5=ADq1&-fnureD+tw=_oExg0l3HZ!VF^9{pI%_82L>B+Yf&N0Pu7%qi~ zhk^6H8tB-?G+F1wc<)*#=GZL@In(5g8$kA*aAsy4;qYs7`@)Z=Hhk@L%(fY+SiyT! zCYsd8+`=mIBZ5n=*!A6LWg&0nx}&hH_ZX>IYb75&r8y?%z^lba#z1-LPu-=Uv8QZTM|Y$e0KE|{$FyQfBQMeXx~ zyt~^rn*@9MY;+0TFtT*&f?(zhwX5YCE-7D`)hf>ueR3W)nz)6~0vij@zlaPxS>WL{ zy-qGYS+Ly^WrOA#G-)U!5%24Al69&8Q3lz(oQ(6K1=%I+MZ3JaN;uhZT1B6+%PUZ2 zJ*u3?tE}y+QoEGQJ#AD8AKCj)7x=4>uz@g>&}S{Z0S zuEK)J(qK2yFjO@}H)h`K%(@-2_ya%98(r*Rb;$5qW-ZublpRXTdO_G1c!nV2)88PMO^Ud4CHZMzUo0nV($q`rX<&93o-p-cUx3A$eUDybA2bG> z^W9BR~bru?Fi%IGNRmIlu^oZ>I)yi6AZDA%u-d2Y(rR{WO8zVJ1vs~yr4BW zLA2Md;FFYh;~_F44Wo<`CxJIImK>6E4Z>-Ua019FJWYnzV>fXg;%U%+F@ncZd(wml z>FI6B56OZCJAV_zx9rX9mg4XZuMt<56qibMJ4}pY;*#_X>8SK9GA6<%a{q?zNw|ST zH@M-K&w715d2fR|+nAosq-BohvK+1eg~Ofs7oaCj?i;#){{3N+^(#+CIeSqrz;^3` zkX$nXQcQY?8VLCJbQJcZFcrJG;eZz=Y`Nst{dMH_UwN|K9FKYwz@j12p1~f@3>I&$ zMB(IKKwlxzUwKB_Spl^Uo31HUf^5OI@Jh09C)9R4VFj5|Bh?(^4>g8k+qfSgMLXCp32K4581}V5p7nHh5YK5o*ZL}Os899`iT|Yr8vPj_5LRDqEsu$IoLg`bnT5J{I1ALkWKGC-a zPfO3qXQb`HGx}cnB=mbWeQ(-H?Dg@?LsY!|7JYBgN#w=TPt)<7T1_+H&pevJtnXby zGvFDd8St#9>3FWA=_dV^_LI_|Vkh-K9Xu)RJ91LrcjBb9M?NLJns!RxlXpsgwdj;x zK5|AWT@Qr`JUZYZ$U`9r6*%J`4^x!aH*c)yn+Mswh~BbYed3H>B1*0EPhetWSuJgX zB|=PqS0J8&1ZXGlT}))=;=(PG62HX}j$f0mBs4j~34wInO6mwF1{_M#B1brBjzdYF z?9j&qq;T>mhdxd;D=AwX(wKlboHE1#I5Hx8hw~Tj$VA`_74$pmago6Mc4^!n(`-*rW6b~_PWdiKQxX^c1B7z63 z5!h|QXrPY9NyUK#y_hwse>J^J9a@S3Aol=ZmWT{V$dH5#xEmIiUYBhdfb?{vr(?Rr zAy2XbpGj1hq89~Hq+&5uFAk(a(`eO8%r?nYV?()AluJdq{wN3dAI2+%$Kw?jy;P2| ze0tEHuHT~!9x5Dw!^Kc$cQMx_*kS)yTACp_)IdxT`_YxrC|E&G-ryNjElSFcW*d+& zAzwU@5|wTADT??`pR_z06EG`)A)mMp93A$?aM~R?>Exh_bqH=FrV)$NEcwci;_`bDCidK^n))uEIfw?K+z?2l_ zo(U=8dkRw&y)7lI4@*&M<|c=0rX(xD0V(02IYp`6L&E~2y8`jja4{iV`&F{C^rPhP z(gVq8XfhdalP4|H+XS+%iC4@bL@0VT3xXM3Zm|9?BkzqI?HZ_;1u~>@Vun60Fc5q$ zXFgJ?*DOoT`f;j5KLabu?!R>BaGgDebP%0~et{bUJNXQ4#D6PRg3FgM+5UgZN}{t_ z>;5ldC5=C3CBgqiRwDinEBU9aWFccEWBxZ-$+CaRN@{<^N+hz@R+bB?WX=$!Y*7wE z+vR}826Vgc;l~(+aN=oUUsfHLc&k$oEoiH&bXoxXPI!QF7lX!g(q?1=6 zoxFPRr2aCblUE>}?2}JPFQ=W7{sigdPrap+KvFO17=^e5KpLd z60mUT1nV)Pj38sOQb?a-3Z7I-Nx^s6QWi<@eaVK&S_%tuvK4ViHe@?FEC#Zb!pX8? znw+haj*`PB+&omaMOGwGGd@XxV3Cc>*Rud8A#85K6M_LwcVy{fMQd1|oUM-uSQX2t zY<-+)3tP5iOXC7I#oCmumx*y<>zZt-ED)#I0@?bxVtm-PC>z1$5I5JWK?54Ytt@Q;BKtL~sWq`C-_MG+*6VzD3A z)qZH@AV{c#AeG{x_x(8E9Y~bQ#Qp%%UoR5vQgOhp7mEX=`75mY{8y~ff_R(0;1b-4 z-UR7oOFGJ>qg;B3SWUj8M}^S+Hk0p&P1N&N*raP;vFX>w$LaGgf%W^tETyn1>w3kt zB}S; z0E7mLNrWjK-L(s%)PBh8Y&(3h!LI}^(P*A36ZzdjPeyfmkC+pE60I^BB8`cPG)hZN zl7xHz6o@fMlc+d@rvQ-#PthD^&wyE}W$$vBJp;0`l)Z~#_6&&1GFC1j%%14$<;{uV ze?+iIP*y zRvO!qmB;raE6or~)_;_&7X=2OyVCUGfi&f5h(Ftqz60rv2U3Bgpxo08$NgL(j34obXzjIEk(I-TeC&k(PmLv_Sl#J*oJpX!nOlc&_h}?o<T8r#h1*EPwCAmY${ zAc-AxVEjruOlGB)Whv6RVy=E}AO|BP2V%@%h(UuP24zDG8fJ(=WM*nvw)3B5blgfM zqH-VD7|UGvuQTi3z8p<>`o9}T%caYPHjDP}e= zwx>=7Y5s?!{lDO7!oC0D9Bude{|=5Oz1z*vTBvCd!D>40@{G6qDmDW8HIj2TmM&?l zd{W;UJSj!wQ+gzL3TrKvzy0v^_z>>($Dxclcm{dCN1pGI=Lg)2@dNU}`vdnJct13p zvYM&VM#ffFB!@C+P0u>!L31z1=Hfe#_o6XtPzcfRvmSzzEbI<&yp1P+yxWsv!sTrp zcS94*go|iB@&3-U+QHY{EqzC*)<6#Y4oWqi*q@yIooA~_yOJDQt++_4<}s5))t(|Z z(bNuR_hrlvh)mAeT*E8jzWx%(hp7e z{=L3!>G%4x)*qzSr9VhpttX}Sr5J5ijJBnx?6$Ygw0_cGZ2e>bbe2%xKWZE9z)4Yi zoGt4GyDb%05ksF-Hbhdqcosq}S1OvTYAocI8c#{wTLt!IUyH3pZ;@weJOc;1TZ8g= zrL=93Z{8CE74;B(eQ2xYP4YpF$5ovRaTX(#`Z3V%P_uPt^C0qA&>dD%$DFOt1E-T9 z+L$5QnBg_V{JoB97OFF|BEJ>+Z8|hX5@dU{m3nU){!;tRQV}jUl~0^eyiXv%IWsgh z2y;S*wd$i-y6z|UEcawq-_edFsN0InHfcCjw+({|x5*4J7G>Bjx<%+!Jz9)Ns1W%r zAgK)`wGlP|wDA}KIF17=3}?{8p+8J*4GtR*^sGS7DnY4*?T1alJ=02I3|(;$6ZVLy z8tsC2p$PB7fJrJ9CA~Bt>!U@Bqy$jO3A7~!5+8(%_?PlBHecD`)Gm;qknQRY9F#;gZ0_0!o4aa+cvpI|udJZbM8^WJXe{J+sKrv@DHg|l{3^~LJ%9#_`CO>^KRXvbILlnXK#Y&V@#H z7tbBN=fYP%GZ(%-%Ur;>K68Nvqx!kI&{6Bl>X{3JLQEEjLJ-S9f!eF-~^^=s+$tJo6(DlSeZxtDXNbaRU0nzqE$rlt+ z_M}v_^rT*FJ%vzHr?6HO_AC~4wqmjYV#cy%6GEo0wE{rBlflUNS`mu-POLJ;5%(I; z=#tN!C9UoGVk;sgf&*u^9xV|=f4NWyeRK3o)yF3aT7xH4wtO5}kLBZtP?auwTP?#O z($skJsy{l4g}e6(A~g2Qnm__yLDXG8KWhRBU}cHmz_2xlN&j*Mp{t?I2CWWOTg$g+ zs_g?Qi8crbbPsYuDOLiLT~QF^+=31De%KRWswr)X_o0P8xl#4agJxywRGhblwG6Hm zt#Z3cm!(K8y0_NSL7h64(mkfC>)QwV;@VX-&Kg1tGIT!2#Ha)(4B; za4dRl!>mx&aP>taRbOCnV@R(_go*-&t^jOWSSYL&Os86flfb?#Gy8;p11~ievaLN+ zRoMD-V}Rbc(UUK_1G3jCEaNPGeK*8Z4pDkGB&%F_rS%LnmdBRvC6G;fVI-UOC2R@Q zHgr$>Ecvybii9U|4C~9jOQ4ExIsc&NV|y)b|8*wxOF#VQPUt8T3E@E!FhoL3XpM=4 zxBpyc;(MP__rCunnnt)6b28?g`EE35$PbLNkcv*ZpWhv#+219prML3{@xKD~V0Im!h%!1eio$cu06(VoN8GY&%vdav6%V}vR>@GWl zXC&$sQnt$`QLhkqmPmW^U|ylmBA8d`(@)ba5;eP&?yAP0c{Br_OK1i>gEWI#qFy0o zyW%D46;eu{?KB^rF`6%4e;M8(uNd~1-b#lEQ#vH-f09p0`_hbArI^H`Rp!S%L8; zRD%!VqHJow37f`eE7GWJ6o`l62Fp5ZE!=2h7;gdz3T!v9$;e@Zr-x0(qF9(s#uB#7 zp*9?=V%s6{-E_}DRy5l-Y|C)FH>_;OGFAn z!3|hA?J7& z+)lCy<1m^N^Mtycz)ym595oTng@aj_#>4Bx45OkK+if`raiLn|_82ZMECa^L;3(7* zAsenI5CfXy@m(_PG}I*pcA8<7I)Y)RVQweLV>awGqG6{I4Lgm=u+x|fJ59V{r-@gp zxq-$o)SzFPp{53gn#Hiw%!Qq%4R)Gl*lE_HLiFFNW@-qEQ&!`dC#Jw&lLFZ!1@@X0 ztSWI~xTnBolloJejhKaQfL%w-?rpQlqDC9#p2B_r3PVi*UO{4V_@0_nr8JOC4&Co@ zq$OkH4)cqc!sATQ$)N6H%F3bt%uvF&@nlA7+2DU}P~kkZpTXM@`h}fLsQVxG)Xkn6 ze#D;k^kGi|V^8Oz1OL0QCzaWi8(53~FJw<|{fIs7{MYP>^R+SH0RO|D{waG>8GHKm ze>i)3p_@I`G4?c`sE>Mzsv}fDQUyDNrK%fW94NI1q3*t#sk`+y>uIR3q4I_*W9!m0 z(sNKxY=e4Y8`Rm)EpLo+Jkz z^UV1Ldx<_y&qP5G{DGZ`z-EzW(!!8JPvaOObqa>I0EHPa?GgGP%F$yqzj5#IV?=B8 zl#eO%iM!NL4eDx>MH(!m%51ik6j7JM;A&rd6ZHHwLL?80gP?rem$*fs#{h6NcM>_- z2-QdhJ8CkM9!RD~Rt_i2C)qw)!vQAhGf?xSjUOPCvCe3xbOa%;dQ`UD;uR1^l4%;2 z+T{u;X%U6qT!EXI*b0AR)c{$z#j9OQBcC|xnNat=-BN)~G0uVUa-Z1c7I;Y9cT315Rw^ye;*{?ys}xC0P}=DKM4PgWeX}8!#IKaH z-Pj!@Ldis*tK#%XVvpVpn z*OL}D4!lx(VwzsG5|kvfWxAO^)OkM zu9+6H2Bs@5M-f8%FPKOXO6QxDmJNck<3)7LsB0jPW4i^~1=AMLJ%C;Aw}1~B;Su;$ zEehenB0JJS^99tFK^l|j(A=)Kt#XBetA_Km`df)c!>L3cQCc3Fgzp(xvBz!hNu*;N2Y~NGhoejf zOruZIKD+{*G9%LYvS*>m3^8yzsoduoFiR=>u(YQV4eD=kEUBbGg#{P@@TY+Vs>DT%ovjT|wJR1QxvM zk0Fa#DYaWLplUI2EF$h{qQQGn&6X+HR!qURVv1cFKUbP33HrQpLAq8K^lNtu(uI;q zFA=9prGe>ssW?MPB%ePC20cR`EzXpDfti>^ldx^X&8%B0;HFgp#qTtwaLzOY3%Lqy zyjm&kcQxpBmC@5P41`*h!bMQ((cZ6jDrHMbFaqE^)(+Z?N>B=m#(+)4DWy~C(hRHE z8e5g+DI1@ac`c!&k<>pwRj3;DRI+0Uu6i{G$4W8k?e4{KO&q?91K_v^oK@y_;g-}o z^7)zh3x9&8HseQF3Ny}*rCQgGB_AA1 zda%@f_48P&$2pd~(4xLripE$_H5E&y8GW&p2_)*U`1p>jqheSB^h=Pd z=(4R{Be4@AVjTU3H1_0a!mp&Fl~`J2YQmrgevEKB(H&SSA$a1PtmSLWgP1@*dDfF+ zOld|8wa^~KG+BHih2Hpkc49<*XD5bmeP3ckC-o3RE&C_Lz|Ea>N^oLCFX>AR(HLxk z{`168%YU92QUBSAA#Cg-2HQ1*Ak~y2Raus^a0M+l^wn1>C6Hc0)hV1=vZJoG#y1=L z#)axNTq*8d5e)>Z83n}NpiP(aGhbh$67tYXZ;W&%@gq5fM`=nMVh||U6nI9 z5X~Wquc2^&h{EgEo;32@Me`7Ws*r^m_%~wRPwJp&G>Ap zb_Y4R-4n@Q5MgsEcAw9(g%8YyEZ}dG)DGbcc5|`>JI`QnO60xgAjom@QlZ&y0f{W> z3rH%f{RzscIA~$IUYKx38n^O{(MulM6i`FvWC~8|MS=5rGaRGaJe=H`%qc09^)#oL zl95X6v{LObuOR5|)d!cchM@mK!TKS@%VObvLpJR2I7b35@Gt~lQpZ9wzJj$v>J5fO z8EBoH+~LWn;^b~M8p1dwCs-Hr=|WQTVDe!5l7|(v8G^5RWmg$iDH?CQPo=o>hN-x} zCy+#L-|6w;vWCq&J#(&R^{LG?Zs_5ONzWZNCq0Kl8ZT0Y6_OGEgr`3aTi15IaK+wk zVOyhdNaJ4&)lU#YYvX5+&|Wg&di9N*;#y8q(m=%N%tMCYo8q8oUc zYG>aQAYVLKbVE;fvS9(Y3pS7kk&0xtkxQbUqKHA#Nh<&7ab#pFUMvHJSO!Y5+bw&d zdy7Hp{s>Mn7$IdnnIm)Ir-xi!a&d4HqjQvn$h%T6gzPXb;fzu9B=XfCJ(r7D@L4x4 z>aoWq^KKJ{kcCl?Q~Z+LAN90~Uz1CBd9D;UlEz)0oQx@$_M$<%bv@k}{fNA^%X783 zo_JsITseLLALTM*8l;kKpu4xMdZ7{Cn{Bv-4-HaIgMI#6o%;Lv_I3G?$GiAu8CiwGFE}8%nbDw;&6jC!3cW z7l}iw?qzDhp+GnTb-+PL5DnHm9-Df%Q3rLwEUBtB!_Ye_2}f#5r7>a&nYIUA3Byxt zXshfU-+E#@0%)x>*{809t0nA1b$bvCq=FIzcSP^mqg2-VNy6Ogx{fF5A`iLR=4bK)%>A9NT~q|tb8=$a~r zR}|IrZ`z~KX|7cYA3ALeV8+;$!j0;U^q@Io(Y3+#Oo7OTZje-xD|58G4#EkdCf%zBE%_N*wMr?wFpK1yvV&1QM*r~K_R+Vju zsbFo*qi*5Dupxr?Ubxu2%v`5{e@m;A?RI-bz36w+tE8A!)-$PA?0B>$)x zNXK(LO~-Tc44m+!f9B8(7RkSeX23H*GvK*~0>HD0em4UF`W??*^gEvWX*m-Rpy_xX zr|Hm_3XZGg5~kweT|z z7_SrXIv1H2cV#Zy{44+;1K?u-d<=k(F~E4+gSU^40q`*fxLPUQ{H$W0c_wVefRdj- z6P7o@7ZApL%cj#3A}NH~GaxEf_HGKZXTYS`*t-;F&w!-Fv3GNrJz?sOXYX>DKP^fE zeGgc|>?vB6MD|{74YNNGh?Cd{TbMn?I3=0A$A#Gw0(1&{j}Nn_n4k!os68Vg%$|_k zMfRQ;W=}CmF|qfgFnfy0ip1WN!}RH2G*kD_nJG=Io;*{ZIDV#5vsn$->`;~9J~bSC z4})bCG7Le6en`i_sYQA%(w8EADNR246!_3Z$<<`bwm)r0I*0K4*qhJ#jKJjGv*bLWWhyuo@XwGX#)f2mtg$x;R6*7wPvR z{XV4M#}Jqf1f~Ol=|Et*qHVq)tnIi!3GBNd9C+^nAb|8Hq_07GV7hV-((ggKj&%J! z&KKy~guP#LE9BK~CSir_Y6X*6>R8Zy$FIiBX2n!o#QKl`vdcteyn_NtA$;AMti#59 zxIrFvi;y~8^3MSRlYzjZ>H3(!bbDG5b}6VR{6m0HzvjUF`mHi3`S~fz zVC>RT{xqdaRUI-(vz1a(yAKPv43GUux*w$`($b?)dOS)4`bDVaBGfQCFkL!7fCJ87 z2w~G1L6K6#u#_WW3pfi~z*#t;FdGLHW=lSChVBc@kj@il>gNS!D#9~xwE3f;h_A!H z<^u>lIbf|Hz?t|9lTvmDhcZ&|?zsl?(k+mes=@bPhn^gUDDyM6o~9%0J~gkel@|cf z>&T9Mo(yRK>~C-F^Efjur%SsbXH3HqE^^XEPm_VKdZt%{wf#$>g2@WniQYoRS!D_@ z6F!#wRHjgMDpQ2wp|%?nkg<0k(Is09>?2&TP8Dv2%Gb?XF&Or}VXt}0Sr z_y(gtMMRtDU|UA{ahAU}h|20j9_UmEcUJ^~8Qq+qlx|d&vh8f_!|=F_*A)x0veird zt9fOHeuJBWUhWG7O13^gVpb3;Yy_ zx~ngcUWhOt!QWCK=(0QL6J2)KPhkiFzo;)Iy2ng=r1MSB2{F^l*yl$fdZsOoZf+sm^9k{C!`leK$T~LaB*WhJ zjJF=l5$wxjACVj1_RR6IlERz7L8PUPrRh1i93jw1J=Q}Upec&Sslq4Cj;YxC$o_j8 z-a*uA3`~E)dC!@z}32he}kgv9nWQ%s0DY_yg@I(p-v(pSwN64szK1cA@{%I z$^Hdvpwf|ENo+z8HE!YdC5 zeJfW-lg00OraE}7_n_dZ`H+lQ9|ePnq_f1GLoydk%pi@G`Ei`+nwzv#=I1#$oiX*O z$_Hu%);rOANXG}mGpxM(&XCRzh8OW-!e2@Beb2?bW9hxgDkw-@T2yExXlF-nBg6iR z*qprRYBKAuo{aN5D1FszsSt-&#)>ANJOv!ej5P?ufn`)b_bo4=zPhl#50TJmP^Q4j zbcktovPj!s5%`d06poU_4?LGyJE%aR4Iz~ucnSsy*sF^oPFq7sU^IhQUrCxj@Z40w zZoN_WD=qmj*lxtQ5yivz%eZPj=Q~Q^kj4M0-O>m{F7@p}j~-&0fy>E7hde{hVUVI% z0w>A1Ui2FV;6b?)g#MEAD72mrj}{s)I+tuaTnYk24ov=1D? zy=1_L9{+{G!61HcCvCGM9izcwfot#(dNdY(2RMBT_i{%&6&~7ez^Vb)E!dH{`(%W^ zlSYcL>L-mKda|oIWV)n%je;h}yuX0i`p1$qI`CyEnnWC32H;WvhQB&ywZ*Z70zYvf z8i~rgfYZ?4m^}=*a2{O&LiN-)s136Z>d(#(I%(r0Xr9sd2D^wGZzg=`eAT#pXB@o+ z2X|dkLI}ff|BPpd-A99;>W|WhxQ^B&1h(7_js2z0G>4sD4j_HwxOFgn&f-t~hF*!~ zU-6IS)A@7v0(P15`E161%8c6!PTjannKZ6F z&qeP48kaJ9nTO^Pa_DR4-TXy;pUnLRH#D-8=$mBUH@L`=y$Bto^jln_%3od~_kY`! zP21h@o%7YqT&kgqmZMjbArVkl1zg$0NHH_=$#?VuCjM4N-ueNzMX;CXn8?W=ob8s( zN_H~mLAsFBd1@XYUzoEom&0orI?)4(gBkBOx9o9-_s)~~60MyIN z!0yqVg1g;%Qlv?}Qq({9O3^Rql@i_CD@7_H3(`Re2D;oyUtS=?2fBPlWe!p~(Di_| zlHIbit|6lfb1AM@g4WQJpnnf@i)*@-5llc&4|3%ju#WdmY3-fz38~0*-EAOosMm}1 z7JZpVc4oN-^5osG|M-jkVx%(Lb|(TUSMJma^BhnMtHdw82SFbVAQ?6!00C;T7j#dXkdQC!2EEZuWuM% z_eY{5T-iq6-BJE^_aAzHm7X?QxtYxJqLne$%5mN3b+A_6Kn{7)N|xxSp#wORV2QX4 zGjUXRD@iXfF;`zO!qvUN$iw@BQK$3*qwAz`l&jvln=!RJdc8;sNsA9WEyL#;#*@ph z`|%h3SMUq~v8TzPid*r5DA#gg!bCNvadcr%pI7wQ*^;|LkRUT;kA>#M^hp##je>BPmMxy5JvW-YHyK; zhmP{+u%g-(*u)7wc`9UI5x2t7QNut^Zcs)|Hozb43jp_Tc8+yjmdP@zeqRutX(-5c zg1j(dW21Dn%=RI}34PZ3^C5P^gN1gw&`kRqqUdU#Cet*y`mh1Nz)n) z8F?fTXx`{72dhJ#&m*v^vyF5gO&@>^GmH$M8X0ENL%OA8vFaMd8>ha4BE6_1JVSP< zF25CULrJm8#5NxN!Yj)nrQ^Fuu02NyN-vTijO6NLWZQTY%cXV_btExg;F`>fY4K#% z1+LWwDc7SmCoRg0MOQSGyY}-mjdZ7R%HBmjDR<>DOw95yGGGEYH^W5xJGpd%Yo1YT zIm3kBV8V;tOkSGc8pkn-o+OEW*HohcZ$}p3MdbYwY&U36w*wOKGJ1}t!XIpHQN^rWfh0Ck9-nv?g7_IFP9*a=Q{0ecme&iZW@ zC}1((|7N_)#``Bq*&LAqfo?)HDhY>HLq$UY2Vu)*lu;k2(_$RCqs%qJ(Lo2YHpMOr z6M(8{kY^0pQPxEfT=!O&H|i!M=S1X$@Y$WyO&%WS`j96IFpKt1jAoKV=P08;qN~Zi z^IY#&vnI*7G7e3v4c-b+23^(9Iqm#^;c0%FhHHr^&9!4ZEqKrQI_$)Y`Bq)(vf81KS5PFFuJl3~Etk&5->uuHhmbs2AnIsirPMpqfbMffg~ zb&=~kvyr+RslVx!x`B+i%(ckMNU7#D6pjk=|5`fnPQu9LG;Z!&N?jfqc)4qx*(kP? zN!Hz}*IbJydoBB2$d?SmfcU zuH{lDz~b(p4SYK$U>748yAok6QK!3t6i2M)4^W=SBuUhV>RybzH{CTxG*WT(P@mLi zBO_+Io)R7Pv@E~b&Q3RotgO&LI%m1==83^y_AMG+MQUcFi!jk3s@28e5T6B=S;1^?Vy54BZW|Bc5JNaz7GdnOGO-VZ8`^1Y+#_BT3ZFC zoPR3E?^#~3MJt&Vwd?`~2u581OxU=;{462+I;5*RK{rk0eQ< zgR3QK1Hxf~AHmH15zHt~InaLDTy0{3>_NX!VlV>;KxSYS{99~B|vHIgpJ7w8t z3%{Y|2ci5Rr5Z7A0e~Lz#sOV18vwEaV6e|Gi@u5JT>#tw;0AyZ05HM;kOcr)K!6^B zrh!fdqkIm^=b(HpEw7h|BfDUr{77034ar62gHd)c$__^Vf0*lwS?Ms!rDW!JMytyJ za3IK(Ar*rn#o{2P1(8wO5E*3~BBSg$fMd}$R&)vF5S$UP`K4|HQ=r`hRXN5FpK}qV zX06p8Tx;RqF;&=itvy_`wmQxpY-ZP?LzmxGpv_*hyq_-t*EX4j4A`Kc7puvrvdxv) z4x39M_aQ8gaJWW>(YXfBGxfAm(WuY|mDH)Kd*PIaLDm}FMCTT?lwB1IqoA@VlnTW{ zy^zGe~uT2zHHY(p2z<_0V567#@?Y%`_kC^ zTm=k5rZSFyoQ#;~8l$jDEiALg;n)qG)G`Kq_oUWprS>=rSvJqLqFRLu>v#vFltpx~ zd=&9Ircs#!F%%rAZ#qwlULnPnTkK2H1jJ+YhJp_u2;156sTE*IHkL0@_Jo2kzr+W? zh>W~$qf(>7%TOUyTxSCm{RQqzab>1KV=FpBOyku(IhT<`*SfN;jK4>3ikRoSMvB%> zs^HbmkCZNO4H0wL^5cJyQ&mGkd=K`RXPam@fr;~om90f&J=n8x5=%PLBh%B7$k;p*F|0-J+wUTbO=oD@S|}j z(X8roy4%&lwjNi)d1XQ6SOs7e<;OFgQQG81c`wS3M)}bw??ZVX$`_)1VPBpT z7%x?qiWdOD1prWP02mDbqXD2001&!MECPTc04N54V$O5|>|Q!&VV4&g%sVHQAPM8ANCS;975R`IN{4J~4TfuV_acdtAKk=L!Hehu+5EpbR{!--r4c3n z&yCf8Jyd7^2aZ+Y9UWs84LS#79}_X)B^NDleMw$Ccy6}KE{Ye=hvA4Sw_q|T;RawW zhrh?V-UpKk&*-6K#dR*bBSt(s8|Owv~DJ3&Tm_4X)45XE6ONNE_#IOs*_p_HYZFPup=d+9k5h0M8a@EZ!LO z417_f@JmM~&91;`rAJ;~us6UiYXmjN*xg3UYXp zZOE7fx#vBpDBid%jRCNdwuMm9@HUtl7P;E_|LE6b$0FCFb6Zc*AopKT|CB0RW{c7G zOStpX=QJiAQR#~n7CtjnRN$Iy#N10NFPSiiJY8K}NVfjkbpwYh93rk;UDqY>GH*i~ zODEdZqtlbMEDFyc=9?sXt84t_ta9nkRkc*=(T4JhduLQTc%`_$SfiCj7hw{8hkGz_ zs5W51nR>SL8yn@_q++q_VtXTtdxebzjB9-3_7T~<*p=r9G0WE@jxV#R1v~ zb1=|xWS2p`k?ae(=NP%Ckixa@CEUIk^q|S{lp7ednnj{(-8+q(=aZUxcN2fn3dx8D zchJd@QQ?SC7l++Xe_mPrq>wB^suf@ZrIs3DMdYmp_frObT5@F7{qE}|YaJVccSlY> zk19e!W@DX>tkyCw=bUfpM*~6PZ(Bexsf&! ztw?4|8XK`{zVY2=v@p}iuab_(+(nrxGo#lTndXFGSmY;J)OSd3BQn%6d-(x~BX`2> z9z#$3Ex%w+`v+Orh}%I~^+F+8+vqMfsc%H~HM+kx6-2|VL^AB>-6ez_*uUVNo{_4b z#G&B$(Xp_5xk1|7$z9FvAqoe18^j+MXCGod_1t58hPQSxi8goF{cG}3vwOC+C6!K= zAh~E=SBiEWxe+f;US>WpVuvi)oaA*}3+(2RPS(cXla}t1LKQi%&OO~|+-y>~9yg@2 zA~@hXYkgOWHihiyPC-N z-RBu-tWyd_n`7N+y1rr`hz%=ULUWmI@f?+QLg5Pg+k9V)5>v!-z zLZ7w4HDFyZAW#*NDjF(Jc$6@e(LPdnZ1`mBaO!k0aV)9G8#xqJ0W5;d9~(Z-+Kx$a zo?J~*uP+#72X{fpJVa96EKo3^c>f!uZh3jkx{xuAqa^o+g1>QCwe}uZ@EPgI9m!#h z@lPW+KIJZAu$~Vh(24;o(ceO54H@|qho!ziQiqOwmBZTmMGvfKV=ugdg``3m$zkn? zz1rH1SFnzBKI7hQ;PnV;X>lLtuq-c=)Ef(iSlRuw!kxW<#gZDzJ)`^6Cij*&xGIP-G$f=s@>wLVLQ>ihZy!DqSF zWWQ>?L>>o-dtRs@TEPX`WO-;rYmWe{fHha#*DTbW>-;R$bZ)+i2QPvDF4pY_rM67u?f0%E1S@gGzK1N!{%Z z@?jzTojknTJjallYY)Q)_CwIFaF-Ffjq;Ze?Vk>R?N_h_H+=ENW*?5Ql z$E7iJ6)U4AlZCNv0EuK(%zc@4J<3=tSCB(7_jrYlreN?g#k&zowC#doqX8_mVa(x( zH~4KbVXu3PRiHQs7n7R3?l}re(Oy$puII5P4KA*R)Wa%{eno6Ax&s`G=uM>V zMc{WRg${*RBgbBJXN&v|lQ8vVIWF8EDdNCoc@7!z~lVk&<1W~vbf`*Cwf!4WtU3k4U2 z6g{o9?GQ?26Gk6ys)8FbnK~GTqTq4IRd9i_Ogx0$HWbTHFniZPYYp!u40q)H4TnXo zl_G;R1tdCYRFrR2)1*LdS<%6pO3F)wBxoAru~% z=HClY*o?w-OT{oT3U9`Ds5n{oKS#>;yR-QeRi8vcDuhTu>bk0UH@lK*C#jf_KakYz zclWb0(As-s!+wy959i0pd;8tf6Zp%+^c*aspPPLU9z>{Ck)Qsf8d**5cBSU&_d{_C zm$xd9gFN;{<9&!E^U4z7xh6#cj4 zBMO_p+)g^0@<;NQ@+Cwa=FA}NkLBOazwCw&#z9QxO3H$TYl-*K{2@lcDsq2Q{wV$; zRrZ3idlrXs@R9r}yr4Fgd=9;RRG2s}(NexZnbAI99O~6*Zbk+(#V6Wz?A}g6oVZ;)1BZ z?>Xltc`5iuKk0qlH|1(}b?iz@s!Ox!ArXdBIqs`+iG zlY-qoWZ8^5|IYA+?|nrZmVHtjc;{ZPT83`5Y}p94R2{bKa_V zYf5=(?xe4nhs^|70*{h{7pcbktiihAJT>E8m>|w^W~=6RYX%3X&pPRq1jhZ>ajsX% zcVVOjepVj0GrtfwEOYI@AXvs=+@c!)RZ}{V>`;8+Ul~yFWSWNt zS5a>_Z=&B8|A^HAa}6RV*y^=!Mwa>5W_d1Gulx%WN@3w>#A>mu(L`oRdNsmz6}Nb^ zSkr%DEatjf1Z%8Wu#US$Ex2hysQ?+x0yHDb%8ddvj(@?*3IUpVqiTK+1B%$q2DRWp ztFKDFS5q%&qSpzUutu|0quIeV!J2PLa2;ys&!koJqgLq|jK-dhzFG`5^^))^a5+?@ zY%tA$FL4cK?M2v|!=WP^{#V@PrEGKsi75L$_y#RiBfC`N2Q{TNEc~_@Q#Q@#wG{di z(ts}v?=9RE6-MgRnh$FFsqznMx(L*qu!tcxHJG3lNg(_}BcKpXAqSN_h@k3+G8yM! zM(;Cgv44s~x-9DCldATg)?gl=oU|?!L!k~=AilUv97}o0zlok;2&mZARKo5YE2i-+(_B=Cpq%h$Yc^8!@l)(4FaG zCa@%Zcwx=9A1(0avCO1DHc4t`E&(H~auu}~VUBht8u2m9&{n`y_k370rb*1-?}E!o zN&VAtc^W0Z*5~1vnsD`<>5SPl5xEU-M2&p}oA5Y*pM>cQ@?j8kcp=} z@)xqH3~n2o%)e$7wVJ`TqK?on;BUkZj$ij9&;LQ5COWiF_0CvB)U_YgRQy3$_%pqI z5pOd*^K57%e_MGRP?3hS2@pL>-5xL#VhRNA6lTk3Vsoulbg7kRZWpWCO;&$t5o5MU z)YgcNv&5Vxx`{;1GlCdPTKoyzwty><&qj+RvG4CD6criyGDlIXvC=Xj&$(F!NojMf z=t%j#xYrE;ZKMR?Y!_$g!NM6jnN*qE7>2$|IE$6iFE~3kU@qXchOTs%vTLUh;w*LD z&90R^T#YxIJLRR8yK7X1f$#`MZpMabG2pI!bJm7wlbU>yxs^VbKA=#JD~}NbnXG1Z z5jkd-ta^Ncwg{d#Ry|>r)^P38)1O_60!T|~oo1-1=2)4%m_DKsa_z<%dP zl3BplN^6-e8o`l_ph*y%mjm`i4`U!7od|3pid_nkM@I_+hkpb9C@eB{XyT5xqTGyZ zpQ4HJZ@_PirePr9gH=X1Ax{pq=E-d5P2Q*M9jFr5+o%&R9E=G&c}$?vEshUczdYz2 z0u{)O4MGK1o3;Q!FR9XL^0Bl|m2bB6$M~t5pK)AyDG5IX7U|Y8sv{E8CB1)8^wEi~ zQjMR~OyI_F(td71Ukp=kcW=Pey`8USo4fuXtsb9BbDQt%t6$+8-TL)rq2+U`S)a^I zU#%}&bU!Uq;ZL)34f_^Sn7*p@F{?`jacV@Xs2b1|993o|mXlV0b?c`!lbcw*Vux&S zHg+;PyN6MYAX0j1%m}gsy-)zQ1tlViIW;)QL12XuRNV9nUl*K`Ip%6a$ z-+m0}%fOF^#g_%@t`>ZT6_*Hnh-&@}vlOaJe0w>O4lFkYw0M)+SVRX48|F*=>)$b0 zZ6RoxvaD1)k8w6X@;;qd>_R)}kXFmL~UV zM{&BS=w~dBiq)VD)(S!hp|)mdbL2Q8I-mJmVGjszb15{g@9~T~tXZ2=FLICFEpks_ z#!UlH41PK@LfO$u&$v4@P{VKmnpr78m~r!%uwytDo3LfgWNymcwjH;^M+;2iuL6^~ zHak~fODpYrI9e+=yKeD8e&J147d>RIDCB&5g>=Ql^MWuD*POoygNnzJ!nmEKCooR* zRW9SpyhL`>HB`RlCMb>NV9eQ)pPoZYj>P`Ncak}$AN8v&kf>1P+rpYUDIsP)t2=wK zHj6Lh$DL>!m1!{({EHdbqts?(s9n-Hn93i^8nkwRF7E_kC$KoV6cxnM-aQ{k^W34u zjK!sld6~-wXdaR{Tfrn`G-=P0=!GKDow`}udWb}0PYQzAxlGi*v4<)@A(ZWd^{!eN zR1kB6E4aq~7&yu;IW$FknELjAHP&G(p;eA?KNs{Rx}XPAJ7h^Fs@4vCQ4+;_S1SyFa4m z?#3Rrl5wMsw-Z>u)89)CzT;o$_cv05x%C0F)uZ10x~6|GX4yUpEc;=zyC^$lmGWR> zto@#rkOBMd6X0QM){3+-_C(ZPg1dRC)*$o&k=q1m8utE?a zeM;i*hnSmI7nuW^h?D%P)nDcv&Tg);FYzhO)Y-JG;YrY?)K8>L)FWjwKhtz0U&eD$ zzDyR6xr^r2`7+7#^JUVSRt#m_cTvUu3N$35D zL&Pwjp`5Q?`LQN4>~!2O#3GD?RXj}(fkCgk@YT^)zVP^aRl5f>&T>AJIfk#U_>Has zo_!#xhcQ}&~qVNZwg$-NGp-h~~ z@Hgx|CilRt`;hNz9vwOdqA{YU>AU*7#N{`gO@DK57rymta4xnf$HiX8i`}zXr z1UK!JCvd|7_XocmN{3R)v1XJ}v}{ zwZ^e*y-kE`ygdyqLnL4M-k^5gXO%TYPnCT5d%*g0L{QF8|GeL6BIg-=RV+Vk)FVW0 z8tHt&ICE*^n@(wND25+M1G?jwR6ylqX7)vOH>p9t)QlM@+#V)euKIObpN+q;8Fq|H zb@necgJo759l#iJa)@m~GwpB-ERQ|08Q8BX$jh~4=4QY>Sdf=%ghUFmec7GYf|ush zNmo~$@3Z^S5lmXWa&^_8d;#)gjOdcu7vku^-eA) zb)G8`pQr5QIhg-*CA_Dps%x@2sXuVyFrkC!#|9i-Xw6U0NVKs*2}<5Eznzzw-u~D% zRrePOgWj!W%tUY{J)u?P<#+~xs-M)EU)zo6&Ha?8H+MV*A z(mw0Ks^hYGW8EolulC-pRSh~X@|in@BhK?4h0nF1eA=COyuJH|sxvi|w?(JkVA|)k zFLiW_=D|VZmTkMUg{Qi%6o15pikgY?z@|%cDXy{o!5T(XH|HJk@Hf=yHoKg z?VCTZI!@<#Eq5v&Xz%!6)%iLvve%vRZg21Sy2{Dsz2Z*AH?*I(tLiUB#drVQK5tjm z?M1#8W~!-u{dZLpigoJLg47}Hp`Y@3fr1p2<=1@P%LS=>+e0N*4rg4a;!N+1_Vs?s zlhmOFsbG7kM?P;?LF%>k^#|nh9xO;LYY&xC-X%<7c0uZ}_Vokuc>@bl-?xW`=JVbt zNIl%Xz9OG@olebW3iH}SRg@>GNI`07`}$Bm@27&)+wGw-`MeDUsTbWUag>OMm42$+0_2m@nXhDPn!{(tCrIJYP+NbO(?y^|H zh-|RMd%Xap! z?PpE3h85{rJfl`jvnmG)>|asLzz$Lg<6{)zpn7GRb(F7_LTKCfsX-BIRFEYZY0Ev7 zJA-dnJ*FBX)|hURco>m@chMD!<3x6zQq}rDt3gw}%axPt;>z(VRT8ys94!?7++wUL z7HX**f^Bq-rv7V1zlrEKEp#Pk2CwwGs6kQdiX#{(70&}j906+EAwcO*@<2&A8};^R zcgCz)!6@3tFnR~Hubn10MfE+xy3rRQeTtl~)*oS2R&XM9o@VkN zn#tGl^ujy#!TVz;yd&Ls5ojHFn*?uz#@nv(ZgSy$Egmf$6u<%7?8_0E8eZMOU37sZ zK0hc79`_sh^K|~PEk<+kzW>K@z}HyZS29vZQ$qgt9T)6WqNOZRsR%hKP&Y6hJ09Np(!O zDt)YU_Rq>b+NvHB{l7wh^hJ39yWRy5{!Rc4L?PA`wi1Qi59I;E2e|-nUl0^(2A_~C zpQiE)ahEE~k!Pf?6&-upHM;1-7|HsXLUEtXJbIIiNVggfGsii+b1 z1QyV5(apYfJ^m-JvZtTth0x77d{dTm14_Zvb~F$fsAW;Q&A1!_fx5Aw}?X1x#(z zo%&GtSujHO1+{PPiW+(7>b4i_@Dg07E^fKjIRK1-QM}Z*;@YA>4{<7mgK_`a%dhn^ z0g*&iysfJ^m9||Ar_!~!*#)Oksmv?nR0`t7I-+_pIaI;BG>!dETh}=J5;!cH-TYux zd?IcaVsE1b+y@eHn`SGKY~{6oZ(~GoExL6#=kQ<}7Ph;yyJ8X^f396TRJ3w;FId6B zs+DghU++cp;4&As9ZSef_ds~W9f(u#1DgW4UW$ST>Tny;9FjIxZTPxpk=WP7e}7|X zpgUHsiR%Wo;1QaDac5U-kY$_hP~gIT3O$3}?3d=WCwikL-n&aK>Nb0U!gNhbgpu*eD{EvGrq#zE(CTiInnCdbO@{rjI6(|`Bb*jh8@4yGrK2+gy{W4prO=LcjY~v zz@^`M>#myv&$gHM3NubIU#Mjdf#gqeF}E9?%d@ftOeh>{ujl8ArPtv;?1{LFC+fUM z^=+`$`WksY@U}`eK%>Ob;B)n917;zD^J5jBX$>1FCesce$OoxV0Ph59^_ruunrZ#) zTjPh$gonec%5o}%>%^AO-IZG+g6tY3Sk&%)F+!WoDP+yPfy;R3u*Bb9Vw1mp!-# z`9;VtLcZtjc+F20OOdw}dCr4-L`C#9W~Pv$E}xgdLk@9W|2sVMBtZWNHib!*DlrnIC8{ z#5ja`ER9Q^Gu4(^*58VgXDRzM>k1uf@%B}xgO3?J(LGyDI^9~_yMrd7o-JOA4qSSQ zr%nxPIIOSw@N{duluMqh%FnQd9l=21Kh$-(qKGEI+q!n^$XYn^FxQRt4*Jo5U`>i! z$kO?UBUn8eFFYLN#8%7CKz$^pVS`$KhINHjg;y{XX&+2*lJyjl_IOG4esJWZ?qt2> z7|l71f|m|f7oBMh3P^qDK$Q^8gU8jhT63n=-}eSKgguex@hDvslOXoiKSQFMiUj`2 zdWs$`%qKTWbW_f>>m<6VAn((jJkx3}!W$q4qEq%Kw9D0u*;W}XHWCROSifooo3hLe zr4z@1&xAXp9Nnu{UTVyZyKa!^V@?gTc8I`aaNJ)@2PGJ0nBm#K4HF$8FbQ0tDhJHm zEKs;{zd-fi)k*(ZfMNlf3giiS=!_$Gy+x$F5M}t#n7;?#7=(Izm#PKRr$yArIiYj9 zIWSb1V8jnKzEE3k4h1XW;fRSS+cn3*|HZ+TG-zyv*CYPlJ(z6gUscDYp&6=i(XHdMCU2u zU~?4C2_SR*)-5VDKQuxR)~e8w(7o-y&JSh$zA$S%E=?{A%~c0q5*n#V+@TsT2_1JR zGwG~jED7U2Oy0eEb$E5axdz4wI@|@+$-5#<*3h$o92+j&dF<;dygU?9qc4Rt7G|a4 z>=9}F!qOo2>y4Ex4Tq%BfB-3w235f@9wcd8%`7J`Y#%gj8f0+JqR>Fi^5^X<7Lg2q z+dDCuE|9@il7Vx%BD$NMMn%Z4FWsT~U9M%2oT~O7KJDK2FD?)L%_|6#%hj5zLXO7n zRXgvQcKpG_RJsepC!*c*wfB6qPwi`YEPyZmpF(Zj=4303Bc%mbhXxNNF6*N|Q&1V?B8#@smsT>W^sYqa@n+t)PL>Jr!}DBotPf6 zZ`F-|N!5+#)IzHI%HOYAl5PD}?P&e~miQQLvV$7_dP%_dkJ`MBK#b^_44O#)AJ>{^ z^!9{(YF$pXh7-;BuT5qbtMcdqIHU-y*WBi>bmtlwdL?>l^WT$cC>SY=__X; zR!|eqRZstZ+E9)DHc@lt%ehCYY^>udvwcfmwf`!69uYM^BTi}_R?}||UD2%}*Xp?a zb~9R?tBw;c>h5z$sw*q zxozAK_0|KSJBHR1{wPjh7-urb>GZog{fw&JIDV{J|4?Y~$S8@lizhxY?F7=hf35pd zLs1alyoWl&TCTgs6C@71Z~d3r`B3QkZd`{XhWsw}(r`obUG)E|SA7r+_cr-M# z1`_aM?J82hwi8L=(m6#f-B5dy@ucX3yd~9r>*eaa4LSVxs>a7d!_E`EjX*A-Z*c5VtqeYGTWJl;I%@ercI@h~+< zb#D)y@AFcNrcT=rk@Rx~M5u<7jMIh4$~qy!cs-}Mh=dzlMC^$!B9S^G0!RPR2UjY4 z-e}85DC^T(+FR$1Hi`!B{0aRiIfgbvTDr=zK{2c0GPULG(W4|1Quqq^SB6d-80Bs? zK+$g^3b#ZIrZcz;>{1=~PU~M$PKoe(;uiy8PzpL&h-V9i5p8-dBD;$?N>s;z6~iQ9 z7pc~{2kC?do5>ZqoV}~&5rnvu`hjaa8SkZ;tQe9lf)K0KH6U$rxz^MzWF z&-qk^&(6`=p_2KWZK^q+gLk|uD+UYG$$zT_&x9&3Hv`J8uE@)_6;ZtD0}6|Nr9 zUky%%!gb~B+~tcuUP4d0;P`!U5r##B(u$iSyaW4A5H5CVL`*NM=45D$Pcmcbg(UFy zX0gvzGtL@6T-81s>JqF(!#?iRDzXcY8?UnLuU)xL&3HEStmvZsyz2K{=xELD!|J@} zLSxnR`H=%oKzre`TP7GoyZI8SfY~9J-MDd+SGwnqxydcVM3VxOc`7#{W*GZ&m%ERY z+(ac?%#Hku8-#5ETrCdZ9ywiKQf!^=4+*NYxZY5AykAo$Y(*c}BsLbZ<+<>;*>W}r zjEPZB&(ozU=dSXP9i(QYL#G`k;=G^a%=`Bu>putJIf_^AOq!2!9=%w=(zZ9DoxEDN zZ&P2ULzXmy{RpnOA|V({)bvbff=+nUiVV8n_m3ZXfC^6y_fy?dp`**Vpr@J9JK1JW zstZ%00TrBQe_b(lSP^+c({PI@X?>`9u_1&BdHO@OJ{9WUi`sj#a}|v}Ej?g>-b{tg zA5u;M3Bx6I&aL4(BZ><|Mc5a#dx&D$>WsgKM)(N8aV}N%Rfirp#4eG+D|&&VK`fEJ zkUJ|6d3H>_@^_dksr?@H@h>$yR}K%=kKFYW*{>Ka+JatMiKYCse4-^PZ7>EU|8Vu` zuQiAzPlY2>RrA#&O1p6)&bK<$jO8QysUOeJgvl{r| zI7q4H+p%XL*lNWaQjm;NGd`;At9BNJx*mvn8t~YoRbU4nNcEpRfUZA7-E7*fL~x5i z#i21l7J2e6+OUAYpo_H9gy;B-_+;E-EXL5oE8OsB>f>T`b`JVzAESDEL;VBP3iauO zE8y+JO*Gj^s7cU~?N6DPk?lS)FB z1c3V~z3a?1;krd>T*lm3+_H78H#iQ>Vy+vi?2^!{S~$DgPc%YlpU_Az-C%@4|9-vc7bkbMtpU#LCL}#$t+9Pz5uY(7NkJZ?op{FW1VZY<0 zhpD^Yvo~Pe{Bw)3xG(xwv66ysslL5Ji<=}SCJm`Cw@@FV-2!7VqPHyWqdGWV<_6l+ zpq*mHyhKl_Ti8~_{47j+>WnrKR3!;&&U^?C;l7|;C)XoyEMjBgeWaatYm2ChfbD?*@vl3y+eZ~5uU8x?+uZbq1d?C9qPUVLe(biQKo0K zzjHvShu61&*Ro%#FZ+f*BN;;Bf81a!z)Pb~<^?Z2cURw*!W<-7>aVNeWuY-5b>r)O zq&|XLcW#Ngv@F!%lgNojs4ZooYkbm99jY-H>hEL3Yj-I-7`m;7>N3$eB>vPAPmnoD zzkwNgNf3pwi~9vkMoDlXFHSydKeAsaUDQjMw-JZ5E8aOBpgMvhhqs3Zgo=w;H9Sq~ z$bpz2HPex5IHSHD2%XCHN4WjN3YwMB!od&>qf^&$;XhgLh7#cOuB+)0T5CXtN6Ji$>2urC(m4~Yz z4#be>;q9y{HK`&rYA7d?!w~=&Yj^I{T{*5oIZwKdQp+na18bx<3xD1ICLoG@tvqCI zQ~t`(Lt50k+c#H+<`?D;~Br$}`5%!uxzQVrs z=i!3CCx@t;t06e%Gul;!YoKaKU@%1_EOL?NMARfV<|h8%36R;uW(l;P3wD#V+;9w_ zK4ePyLS7m26Xs_3wQcg-&~VuAZuJBsv~v@8qq50@@9tZ%x?Z ziA%vW??p+$)MEM8=K2=5<=a;5bIm9U))A3NlYFZ$rL80R=Dk|JHQ=bk*5y)H$+wlR zZ}BSwMMd-ZB6)89Ad(pzL@nXshi(5xnRDa z2pGy;J@g_-auLFSmaIP`Z}@#c+~C z+kaW6?L$|M3iUsMDz+qDDtGFewLYZFg3w}kQ*35ff93$Lls|)tlaGrHrm}bHk3%F8 zuGFL1N~!YMuri{MZ;8V@Q!#1_sTgAztGR=J1OCKFp|WU>A-Pc0ZYyyWaSM^P(6@FQl^t{8tKEC&>&#E8)NjbR!GQ8aVn zI~oH5PG20E+{t5mVO|meuZRCeo+qewjt-Ru7)cn%j36ioN2&7u!-HycZK#i^QB>;d zi+x4Cj`vnYPy4CH+RzX+Wm2ej6ZkU|V~}Z*?uf$yoDIf5TSD~>nBR?2B!@(7lr+bO z`b-!O!*CQ|tY?eFZmBG5f>t`wi0VUo9YTfv?-!+Fba63D}r3Pqb-rP6O+h6h;fK%Y;bT(^3gBt1Uq(z0y#7iZw{*8U}QUS?x zULhk=2_Mc={3z4R}>pb|FxQ+=#q}?QMaeTv_rzTeW`aAU~MiV!lP|^@fst>QBXL6oW)HM>BXWc_CO)E6Q zpZ0|{pDTn-Jl7d^mH?-|&yHA(WE?mz8|P8nQ!Yn&$yA>IJ4Ti<*UMM+`t> z;=(UYu#4t;E#|`ORPRZl(kA|x+9`kwFaB-7`2Sjb4y>fX>q;t*|9gmmsP(XQDV}>S z|C+H=xc&Tze{tGB_guK}nL=YuEA^Nxb87FnP?tY26Om8%C6G3=V~7waYY+luGlf9x zO(9^OAR`rdW7_pXXl)7 zKS&T)UZQHphf0NO?|bsmxDfp-SFJ*sr{0k=ZPUm)WvgCTCjOR`**cSvOS?qg+?VV0 zH-#b@F@?D_XC5Y8$CARec^DJJCJ96`Opwn(V1nOLjQFd%BIBri)VJe82lSG5d08?R zo~>p~$W{AA{c$=v-)~eYmCGyBF{x1sooReCCrK+ zouYw?II}p$!pC82SaUN`fYyb{eg%AC?9a_|ivEp@1(M zrHKM8Z?QBSyv%#kgvvuZdb!E0Aaus6o#PO(KoH(3A6Jf6_MxHDI?kudvcS|2rO}3?)#u-g!Qo3;tOi(0 z&Tz(J&ehDB0|o1M!(|C3H5!n$NdknJ6VgBU7f!Wh0#t_0@X?_%*#%lnVL0zAw zGO1{oN?~X^la{pKN};VkW}8aBDrkX20xOwt4<1SG;w zcB{RoD!+6>sp>H`G^mLy6zwJz%69nra-q72e^H@gPW#`2(k3C>MvRyg66%p+7Qm9I zPvFB^igN}Cd?G85Uvv}i6=PqUYa0m(C5>Z~gi6(mQ$w}B?=Vs&GFNkW9b(aEgo5}D z_#BH^z+|ZprCZE~DH2|XJ4yUNZK`=a+u}zA94@q#e*=EZ4BX*$1c5}DX%Yl<`&fW| z&LE*^VE3d`cpU=t8zTjIlz-teK3s&;DZCDsjWYM(R%+poq879s#HK|-cpdI-_Q?`n zhai1v%|#Sk>|`zJG}?UXZhYY=JygQ$NR@iZ$I2lRUWY$My35Cg;SyelKYF{$$NHfh zUdP8DQ$Dpfk{u}0AF1-gF=BzUK)iChA`auu8-bol-SFuTgKyD3Nv4if&!2f;6ldLs zs`ki8|Dj?{=7HthP{Cu;wtln+HcZ`oIF10QSD1+bYUhrTWi#pjMFSP}uSDjPfRA=s zIt>%sX=!i#L%1>e26|$xLYz6#ps3*p{>4P4H(eFQ4Cp%*iiQTr#{I==dNeem3)$(^ zY%rsGJvw$kMGNozy%5|rkOs?9^6Q<<%!*iNsosx{?H}ZVsT*~HIr0mq%6w+zMg8$0 z`9-|Qd}iutomrtX>s*=fM}uDG<9hvjn=8|MpL~og(Z4rICUfi!XtWdcZ^Q+eTA@Fl zE5GqeIP(ap%ELOdulz=abDdkdKn~s-X)G_vsu%wsp@vIMlJ8wfR+H75hsX8z@r)ym zIIrc={zpi{5lmDg@4ea4tR)-0hg!^tZsL3IzUU${b7T`a@&&6+^7ee_g(kKSW`%n> z$h)^`+7EG>XdeVhCaXG8?iAg5gHGTEnun$XuDr;zdfyb=L{!F^9Rz+{L_AaPo9baO zyfO>d#FHFWG6M^69`M}=H;V$6f>>iGV(}*=ukBI2-Qa>tZPIXmqv~gg=?Or)t^npZ zp81`SM%pCPS-o%V;u~6g39QylEK9KwMocd;@C+TU`Fpd2>DC8=JE-3#9+iHZu%+L| zZdI)taTX{I01pV-L=2Zs=&Lpz6&3p_;Ery^!gL-d8;XicbSvp;D|G9Wh;X(isdd2X zW!y^s7+Q%2d>#@@^l36Z#gH>Gh4AU?`*9_GvFnH!lnf6aFz>S@x)pPh#*51o-3p07 ze9lH99a!!>+~Uodx<`c#^L!E2+zk@lN=)1iiEc&ev?O{Age}pnq>}e)$a%T~rwfJ* zt`ksnE5=~s{?qi(D4wM_>Gh;<*sk`>z6ow7biBcsqEGO5qcUrLA5klk*05=kDYM4_ zTeb_b{f(ywtmWxTn7l8RpFN5gra^YB+pPY zjtxx+#3*COzw;TMQ`N17n{Zs}raX*d9K;3H|CK;h)2Qc3e*_noYOKhu@_hTrr{5G(=eDnK1t z@>?BlL-VbK0L4tL6^Z<|OR`)mqI5zh-7JJMLj}e(va=(eNpoW)7iO&hwKR2P34$d| z=)Iq?W@4=)y*T!x=KN>P`A?Yk139I;4QzlpLm*F+Dc zb%jV{HkCh?%g?!raAK;_MJj84RS*PA=$pL z?aR#1j(XZ4{f8Ezr6X_Nhcr6CiiJEZ8bNN|2xjrv`eh@t`&Rkp{fUBSm6cJa zjJzM*M$@L$RQZh@m(TOwp}$=$zurIQ^WxdL&}uye!Cl=f&iE@*K0ZdnO;yQl2bGl( z9q&l_mO4iN{vi+NeO{Lj$#48nHKVz1g8I23)VFRY#}}c;;XHvJu&w6Wq29;virY0M zz97}uh+>S!ts8PWvsrxqXg_>rs7LWYOfzs=HWfRbWr2pbz1wi}C5Ugh1aXc!@1)R= z!Dcprue2C8HiQArCNbHnt~xn1d1N!;O7;mX>&{T|$3$ua3nNU% z^Qz-yoS#u*d~{=QJ8Y4$_AQ*;`_=mkMh;TLPYLbzF9_puNBoXioEaTS5++=J0k=QIK(4J&}=HWkqeH&y&>GjPs2}7 zhcs$KUWW2wtKq(Ok~=S$qPem6OhxcqCb0_e=N6PfpT`i6s5Br{lP7dMIQq<8kdZJG zvH2kMZ*}xlTlHpbyjU$g%bH@+{~o+0f0h-kv3ZVjfs$VY)Ahio18Yf9_y6IdpedsQ;%YTc znKD2fKgSyFs6$KRgAwCZD1MmbfUtI@^<@{0lDXBIE;A zKY6x`X!zd%GF?Ea*~NxmR~wNd&bF2?kd3#-I?=OVFQgaVn5Sp_Cr=MgMdig~KMx>0 z&y^KVcs;zewU~`})QR&E?m=o(sai9!erof4tE;e$sUM^ql-$jbl{b$DVbJ!@w=CL5 z!c62x6*|YN3~n1hee*9MNS7(`O#y_+(2<_z|$S61<^Si4_2* zdJN+k2N-!av2CfDdtXrSjRl-f!{OP)dQbN}pndSFi?F#U4Ar7wS6#4MCjz5EK%Px( zTZ(5B>s`ddqX5@a!}ThJvuo6XJOK+x`bfd0eF~9y;A6iuppo<~L=qkWIC(v>ZE0y? zo;_T3fPfb1fj}b9CAO91pGy=G!6KCm(8LE6A_)(LKkpE=lN!u^5;z9wX2F%LtoS{H z@qL8;J~IE^9tgZu>e7pG3rghO9|bL4usUBb8C2^pMyPNp)U3X}*m_lT1TV$CaEUdo zs84v7_!VQ2WaYu@V}ll24fEKNrFGz6$4jFtwk{;_uaQls>$IiI=1(k4r^AKm=n;kK z^wDa@n>C0`eVJ9MCjZg$`?k=__3$PtUj$nwY-7|}gpeX}x@R1JFSwS*uIO=!eiP{v zG2Hvq7V1a#GpggOF+w;KV-IxUvH!X1GHbGy7ed9@MKpVrnH5i!UPYHQ@LKeU zVL~hNlF%~3Ld%KdX@&o$)&QH3@pNM{g4**O;v+~`sxK+YH-(*4<(FIibv2&W)flU* zaY!DueV1CZ#HvxtF1Pylq|%$zn#-{T!m_b{UKO{7MMN}@(dB1U1$20~DgSB@14bUz zHK@`xsL7KFuc8{%yQJ>f#nljV=6L`w3VBsIUzHAkgsD0ZvqwwjUX6FK##`>fdz~u3 z!is8U@qk>eA#LoQU15#tCanLJ*j5W}vjz*!)M~-$^c0*%AI6#F@!=}r^}jg{vEOwg zZdT=2!oi&pd;YBKS8xQ(0`RU7r0F6-8pSXObz!8Q1)|f&9@0tqKP{mqS=Sw3{(H1% z{(qx1|9^U5{(t8{`ro^e;-EO5-f9)yIn9g--ivwKA*`JJWdL(qmQv0^hewE5us=q z7AwxrT&01Qs;WO(2Oq@P8#MOm`-h2rqVrd)<$tm!_hLlm#X&`cmR+IV{F8N>G;?yT zw8jGJN6A@g*46OUXKnS|&N)Ll$J2o5E+uTG>X%B_;P3VcYQ`d~|6!MK4?j+tEc(1O zS^A}Xli}6~_kJfWdB%(RykwoK{kpb)P|IJc9eY8zef|n{d6RXf@D#pIbu>|g4es^R zl;5_Z133|%oHGj!E+0yPN$PAHwn#dk&7i%cG~&ll?}O1;vun&?&Hh-;{sWqQgxtw$ zoZU~ef1hTb)+$;XlV#NFC;M0isgQK|BpJixMcm<;q+O*uytz+@7vUk83!BGVHT664 z6zr}Ao(U z;gj>Mdk{A2H*6IHdV30)bX>?pm*vTL;O<2x@rF1|qLlW#$as#%$gj-fOm0_IORZstG?EtBe^l~|OQIehniTuY^gX->bI-0V{8ShY0!)uj zm%B{aOR|*$wD!v;|Jp6)eeJ68{7*T98_W4;s-|b$9Rg@N>m!a($-JOiFoX9nzV3Kz@4BMLWqO zYhke`Nfn#uOqqo_6_;YfgL@L zNyGyHHtchqBMkRp%mB1XUJJ4K3t97Aqgne}t+@`tN?0tOk(#%kG;dHDSW4mTocKn^ z<88-U8dqUv&wZumK@JZ9)|JbJXMy1{zLw*z`*n$y(#Hy}Wr=+Nit(q`)# z$w`b>B{yb^#fGa*H)7?*FtK6k(|lrx>UR^`SrELamfmDtr{Xt`8>a@ZuohFKmo+P_ z-xVhhP+zXFCJ$`nO{5l{R#W&1axk31mVBT({Cew8Lm7`<$?sSqU@c_AQ&Ew!2aAjA zF;w+th|TKAKU;SWM4!PHSDT_=-Y;wPiZE70zN);%>Y@4TrN*{k%0HWZ_`0gA zT5?q{((eXx4lMU&R)5uSGor<`5-m?yHLtb?AIjW$zK7zL&`zy)EDRsraQ4!rt;okg zhj_u>2>m9~7vvj;=44k`lhvz>Fpp=H$$D!1Atr0Zmul8ZL_8GqpD-&G%w#-^^AwHq zG#Abnc;?ruZyOvoOW;CGoQ5kI?M$}N@AGuqM&vm?-7a9733&hI{zkJjsYLo1As9VA zPtfxe4K=s|vdRicCG7rc?<&ix6M@nL9XXlgQ8|YTD&xpJDtH)WMO>=puD1G?Md}cN zi=vaki03NP(CD_ zfqAsy>*KigClfyh9ilg$sU#)zuEW0S1kKxB%6|)nR1q_#jpQpTJ?<9q6&13p*;iD< ztWvdqML?#FP(?F=m%;yPy)H0G$EE9$xSDkSA@?ZI}%)MCwBI!Yvf%l)&TXsPZ3%_fBIZPRg&KReHQ|snMtakr+YUIu@OWBi^0S3TJ^R!a z=s>`SKTMKngP!B_?43SGC z6vW)2RgJyJ8rFoSL{O(!Hqfy?Rsy+akO-S&JWOiJ@##73tnHM3tW$bJr}SNgY2)$2 zwDXMKO~w(a5X?{kE>u+X6W&U~lms&f>_oHwA2XZD?0bWRm`y*gomS)?LW+;GzR-u7 zC4ztLhrtYL?=#_b!=a~6#w%Got#}5VGk5tw3fIHUVg_B>a3kE2L+J3em82j{d_aRV z-%AjDPpI{4v5CmFs(e#ZP4TZk@ps}BN2Ho~`1LFis<{wfiJJg?4aH6T13FA@DK;^s zGrhRVr)%Xr6TpRt7Tivg_gbDs{7qc*1MMbU`Ff5K#-mRLdalvPou`SB7IWM)nxS@1 z`!i3ISOR>n_gRFiBtI&+$dMbB)M~Pu(STV7g3oFu+N5&6SW+K|QstUR4exgYN$nQm zLQLn{c_D87A{t9A{RA`Ti){*+9WK#&?s4NQWWv!fCSd5$dP-Kr$u)&QZbDI(1}=3z zshtaTv)H#O`(CU6Nakivn{bo4TSS&Y4X~`pwV~%R?BnA-VqyJB#lEhbFgEc)2mc>U zvu@L65GlBsp92;(F}U~8u?s~hrQ;hi{IhROXFEqyfc4RfAmk21FkE)}M$hb328;&? zv{9#sHZqL+)eC{+!zeN`l;0im6HO$#McyP9_VDfjy-Cao=XEM7d`F*`%YZnO`O?3UVio+$u!p{DZVpzIp$uD!G2kXyr)X z;LMx)ixhNT%omKWmTwDP-y%xBt$dX_xJI~2zU@Ze+@cAmZkBJQc#F^0<>D>!t-@&dB0)hpXwK;e!w&$uj0K$?eY+k_$nI;)&}7m5R;Im*V%UI3D7wHMWyeK_EAb@J;Os+H>&!mH+qB z|EVzl-$Li;@!`<%V%-u~%*)QS;ruG!oJZ(edA9jB)WbOs?__mq!au2<9W_=Hwda!P zToK~}Eyk6$aQ&98#dw;u#yDFp24eMd(hO!gd(AQ% zvw@sYOu2w@l`J^Rt(Q2IThqU8mfT2}2B?KImTf5NtS)L_+)V*=Tv6J zTz8CS?Ie;-z*oyO1b?^(WR>eqe9=+}oTdq!s{41ApIb?lj{3t|=3+y^WAhAH`Uky$ zbWbcW+2F-Twja(Cn2<7kdW^5)0pxoqX(gg8rG^g8l@;AuMw&Q_iB;^>fh(N$r4f?0&M zs1{~m^ay?w?(1jOEO^xfQgta!t57mVMiM|lqw zZt=H8_}7dc&cOckE|OWm$NukKByZ~xjG##ntYB|Arf3XhAb7=5hXO_1kK-wxMvmAu z%mHG#;1?Z_IScqYdBZUy>B*WH|H3V=7P3YM!pgkB8%~7&g5t;KnTzyT;UapltjVcM z)5H+I*Udbv{=wbtgo^XEc*EVzbMZgP$K7Md8?LM;&sMM0?9_`h92fLnAs^dn<*j-C zm|8@~qi_(qSl*f^o*bhmYm6^}gU2L|5c+YW@DcLXJQpe*C9OU88!qgR{c~US@;u^J zuh$AkvpJTwhhqhS`Lgb&lVCGC+QxY^1F9RbBrzirdJDU($kiunK*@+z@&VhZD@i{kOYN>lBu&u77-Bi zJ_^fgZMn#6#5+=5TC#LxZET5N`L4?1VB!Vv&X@fd&}U*Kz5HA40XnxgYH%PCkO#ry-wbKKzLi z!H_Y<$%io{Z>A^gOOL4K0E&L^27`|uu<9zp%nN~0deW@Rhcs^pC@$wQ_g@Y{j3>eQ zhsQz3kichdk0D`8KQ3RHZT#NsF?5(@!pAgR6cqih%Tmn`UJgqk;4`tI!ZOvpE@`SS zlh~kK$$jJCIs_GrkHhktcZ3i;hTbe?Rf@isQynIl9^NV4w=f+Y*ePulrqiP-En@Os zUoQW|S7bT&jsO$1YUTcr2$B8dLC}{zn0hy6b+xc$xONbw#cI})9VI<~A^*aXVa(bI z)muOVp;=({e9=P$PkJm3Nf?fR%ViaPZHMXn3Dn(@ADEOYU_e^_Xt5BhOavjJfIo`+ zpB~uc=A0>Pp*f2fw^?inr3TR&jk$`3X~fRxE{L3ZHtPB1vYa1EC+kx{+~*7y9L|A6 z6q4}g@~L^q=bEKNKG#Ge%(ZXIiOT1Uk^)8zDGmyh2onZk0-(3|?{rsGF4eMuVMUaMGbKRBniv{6_r1-f>0pku&RLy_4`kz4x zz9f25;iO=@Mlg4gAc&pFlPy2J*k!E7~`G&pPO;B-@(G<_M6oeIk=U)67$z1y# zwR;vwx93y2nldrtLT1R9z}j%9i&*kTp2-SBjUo;6Of8Mmq?cfbpuJLVa{DJLe=IY# z{W~eYW4tck50(S>;q&uxOsYPYGV8`k8FS#iIvU>X(uJt@;@qhvx*HGN)3PSBR1n1U z;^Di`$aAmMCtUsFnvZ`d6z7Jx3;HwI&~NP2rk*ccu6tY;XNPoH^J7{AlJ(Njk1s29 z-D{v-fV8YFe3|XE8;~z-Um~u1g7G7bu>QkN)!R_rNK*hp8T%-dOvezrpD=yUFA1*fGaaHQ$yD3 zUmTX_&_>RZkBEi9=u_`-<~#{+aHfXH$glS;SoysblMcYqBYF^>Sgb@PjC2PbSgYPV zSz4HjHr>k4KK_heikSvQ7P%9L+89Ns>>7?yyBT*#V*S-=H;nKdE~ug(1?Xs7P+cgf zaK0g^zR#gTNL@sb$7^myMFBeh5OmL}=Gd5iRW8Q1xfq+@iLtNM&97KfPnEWPn&vCs zs2ojDOcZPgPpmW7adDgekhV$E?>1S2#tJrSk z(JQuuN3WqwEt(QdiaEK##OASJGHLw~E@Q~~hR?)aVzUf5Tqdc0ecUP&JlmfZ4a;0j z7Lg4Om$Aq30*B`#PUTZVEO9M$n|z^gUDm)*)mwZqPeDgt;@D!28+E^3_%z{ZF%v@6 zZw}_PpAKtijhI9OyCSWk8;{4GB)Sfhv$fd7ckMky9}(`&KavH>GnTYS3jJ9M4I6X~ zFQAEzlu^g*su?H(n4?jU%dJ~T;R@GoA$3M0x`QVozVx>244LCsu(-lQX^RIj&tJ28 zoPg5UKYdv0jy*5#%G+g)V2*f@+3_a~`fc&AdtQv6JEYN_nBElYiJ{GLDO5*#1WwyR zBTH1{d+@C+XD`#W;%K>>?ax$kw3I>k5Y^gmM1OVt7OP6Cx$qWxQ4iDmvh3no+cH1L z!jg7Q-=dXjH7tqCJlT9-4IQ_L+F2~jc32x8ePj+QYFy)5PplSP<|=Aih+P}c%s ze4l0Es7?^zuWH6OH9cg4TX}nsm@$nz_)4ZfdZ}wrk_oPK*W*?Ao0`D_wELDIZ91C> z#zSi6r`b5|^Mv)90_zC|@*I=jzV;#aX_5)o?gZ(Odn?5ZjCiIL(^)SBBC&Fzi3{ZSFb^Tf#%Y4)2nwRHU3>QZZ!4dB~c@1)3{%!&(&M3t&H0b&k}Sr#334?)@+4qkuY(H zD*sQ7R=$7*`@0Z%bdjFRtif7cRN_Ajmwo>=zkxo%sojjdLSY#5Ct6K0uAi_MaDnKen-U zpFCl3YrJh@`tE|v9QPRm1daXYCH{$;U8I`dhF@Y%uCcE{>5c+`oLCd^Ell6KPoC7Q zAK?B{ke6d3@gi#0fB$(gcyk&%YYQ@S1WmYerg0>l&bhI(Z7|Yjvm5%ze8De3VadJ) zqjRW{)cAYopd8AZNW8Jn_M(IDjx(R_814CR+K^jA`SgXI@-OI=KCLkATvC`e{us)A zAhX~&Hl?$Fsy?S~&!Hx#s_E}ql~bf(1r^Hcqq!IbK6Y1?^Tx5>H$j+B>pXSGQ`Qiv zbtb+4T1Sr&rm(5Xv|Kw^EQRQF$-!UeTRDNEFp4$8hb_Ch{MPGE+17Q;q=t(zc z3+D1z?q)rZloaIU8Z>q}h+k5Wm+Khjp8@x5K^|1PNeoYHE&y*T$jkvI-a&nT-hW=~ zNHDs0|9Mo~^wxdySQ4=nfLn&VQMum6BIFt-;69wb)D5V6Vn6PQO;laRlDGo}`?(9c z)bm2rsCPkL4$fQ(Q8ez8C+7Sbz#UYOmy?8vH?gBH;>GArjmunTeupYGQk;mXKI!H& z`8uEM`9?X&gYNI=P>Tk5?^kQD)EgEk`qe(zg)JZ08d8v#YxM*?-P2Rtc^Gl_V0DPt z|BFjh?Zcs}_STQB&+xJcd2=TpR%<@NU1(0=Iq%Ketowu8`0{w22---=I|Rwc_$5IC z{=C>E*zoxTJB9!E%y)r$zZOu(mOv?Coc~OV4Ny;iY8}a??U}0lb8E4W33)%n5d)kS zvx&l@xE_-)ntIJu6bZO+U`GChg)YsN8K+vmfbWZ7N_EbL$5}o*zDad_iPm92&oI^c zKlpnvUSwp8RUDm6qU{)ezyjL^m!AXhZCGGElY zs&mosURTlhHTj~cYm~j_@L}yoe`O6S613qCwO}VI_y+TK-oE*1cm8o|#^Kg5_0Ts~ zUoD>}gcO5&kL;Wc|21Y>u)|TXlXUM@Yrf4A_m1tH9lp(#9k*2Tch=9NBV{z_dxKOw z$Y>*YxF%dI|EC7XZ@j-wm#fX+W0yHekJ5$vs4u_Al{1D)^>Lw#Jef!5#dYi~y0}Ig zDbi^DE_9wfE_Crds`pnD`m0etSSR_yWn}+1wXgWWTIto2-L$f`dhk$@!zOsSfN8`$ z;-`5{k7EApM^}DXJxnNhHw4kiFVD$R`ebBe^ zn|$XmdM*<`N6;I1@0V8;pR49q$M^Tu66$1)n$@>@uy1E~N^DVf-|7aRpg!GQY?!-P z#$D{h_TEPIyLcj&(S5FVn$=N_;b7HVQe9agT#Uihzy7p~6Tlk)E!Sdmg|>{C+i;C~ zr=)s}K&7hP2t7#`!U%S>a|l!BZzHrlE`(mJWqoig-QughNVv2gPz$3a9b^c1G-3?LwUD=!Dq&;cp{O{>z2f`=07(AK$;d zvTJqUB3~VK0`DCv+^u>d)BzphELGmEy1y3kvuaH@G@!KEv+kS>cHB^mMQm@vQB3tH zDHeh8()de@7-i(DJo?mB7m~>BF7!y`2}kaBp---Kp^vXr3nI1sRt-G7MA<#7kM@RW9HU3;;pZU`GG8W&kYb)v3DFcf#@l#a*7?8{6LMbsjeJqV98kTyrb}o ziEK;I#P1>IO~LQpKqG@s|N?AZQ!g^rC8mEio3>D`a%?-N;I*Yb?(Kf@0X(tnBSeZYcA3Oqn265AKsrZ};s_8tC!y8j1CW1fi31F=)}pI+|;<=x56u7YxBMM1f%0uO1Hu1tiRl2}=c zTRpIxz2(i#oams?tR~{et%rKV? z_o*)T=pTNMtWFqdt`7NLafp;B;czc=+$bNSnoU5eabSa%1SZBo z(&zeyxVe^c6;&4%g?mK79(%&wvhp0M6$Lo66zM{|RI(RBU`Y6NPjVfe5_Z7v_(osX zQDv<6j)^3xN?&!8bGQ18E`ni+o464%ax#CEr!oI&-6O&oG|vywjA_Bm(!nD_#i62f z$u{~oREETW#TiOujrs@3`*vCVdVBGZUAwG~j&|Z*Q=C;T6rg$HqjQBo!|6*qQUp}S zt7L_W(prf^aq4YcC^39Jt)3nX$gcL&f$2eCyr6{g4OOq{J>&`$26^VQ&v#{buK4w= z3YSFG8XW8|>|kFSzAff1!8`oFN5qe>sG^U8}X5Q~ET*y0dsOvpPHzudt~e0A zt*J4D39uIU4oR{PrRw^eE!6!s-}o%%JnJBsEx{`;F{#m^9-N z)f`{ssGKp;wPwN{zPS!5x~whcqC0(a@cy!Z$GDzO+y(xW)k`+t?F&zo%^%N7xGn?T zW<-PxLP(Ve-f^c)0h01c@KaQD148VdmugV_X<1p`;rfSz>WZr@F^ z7kvyZSmJw$k+Z&!#4&PljGW+B?%mplmbx%Fhl#Y z`dv2+51;BnltSx3K0v`5t|d>d`59i@SWuWJuE*l#w` z+xom2y(JYwWEj417AN$=tb~PK0CE>G`*|&fQckHn52jPka^KT-7kJ*f-1mXo;+Pso zsL=3rlKttAH}$9d_0s7L2o$o=19Gq{=t?PZ+wlq+x%)=WX zF|vwT8eEf=vM>YV1vwLgtRfoGmr~pxV7ro3IYG<*;QQ7}x_3Is8SoNX8!rcSHwS^F{5F@f)5mi_D#>f_x*Ub7VUoW7>b84TN`Je!jQ^pP& z7r{l-VwcN25x%q`&$vy} zT8IZxR{4V3f8Dnq?RyA&P&O6~q>~T%hRXeLKg!(X>*mxSrV*Qb@7djdMVXr$Vfm8u z&AzbAfss3JbB}cTY_m_dzs#Xr@^zJjwq{l2muGUE+I&aX$fl`~njoLVX(p8sY-yaZ zrkM|s82?&976iVl-{O0ej~}dJdgx)_HyBe-T(pQ*|Is(B)lTSk2|df`G)TVsaFTiA zkG`86UY)CU_cR1umJKJ+jIF+Bm_MvGX2K)B)=pW{_yHxce>ZG+^nX*{V}OU7v8J0- z9uvcq$E$2NT3HQZ$Q}kz$u?h_%+V*B%eMI@Iqh1l==c-9=Vd~VGuLnT4Y9M7I9xY#`V44db6E2Mmy>CCgfTUX>UNwGMj!s~2XyW8s?d+W|r5${g46opZNmFl%1B<3>CQA(J< zR@>=RJH5)wJx5QC@yBbAp<~h z&cUb*0L6)lgS6{K-x%lIf6$LF`UW^d8s(Y3Ng0cwIu?Xq69kCFg)2RAnRwDbAP{}u z+-myL9Bw8FB7yGP=YuN-(=W}H?}*PTd>Rry@hs$G3S>kIah~oWW4~BiSblA%6Z?G| z+?->?(SnzJkGOfCYi*&_m$511(+q1OO?lZ@E_H1vfG1yu0w`O%h4K#g3cBd5(mxJ^ zPCOJ;VGDD^*V8S#wC2*XJRGm>IpFJ*%=)^1^!EB|cT(o|yndAW3f9GuxWS(^vW#}U z;(OL@i0wOQSn{fGNRN6piOj&VgqaMjv7;(HxZMz?iM-e=LXCxC{`FUV`56+Xm$9fo z|1D1h)_AHzG@#F?wtw{v>cG++>t?t$wsPPgh=zJ51k4{#_DH{id(%rrJUiEmE0eJ8 zuJeXi%~j@LbQPw#Oi* zs+qC-)0AVra&Iap#>mwX;*@c+G&*z4*UQcfU6k32a%+9V++~7Y^aZr2*4KNmBt^AH zErW`*9doKXi0GK=5sIa3@=@F>>49%zYup{gO_bkpnps!tyETIgDVtHCJu;zzVzgz& zhiLvgI1Q1Bjc}^O#NvdpiVEMwVVJDCk`}$|TjQ2&_a(*s!?!Jiku%D`#06-06dG9w;62D(^W;B#tsAJe1;wF3V#SqIJ4A8s`CiH5de#JwS{#F6S2*UD;1xC| z;&}7Z_k2$}oYrl${(THrnOJ`Ge^TxHkY*CdztGwDF#@9?i3YrpZuUC?jmN3{K!-m- z5eaRIdFBHQ=yVC^w^^wp9JkjW`_cOuSVRraryXMMgvYWNW|3`8g@Qa4Km)%LyfY?X zvA(M4S3c7og_!U9e<}5(Z>j7`|AeYe`d*zSL||yKq_%N4WcWeZnL1H+ruJ^?OfQt{ z1E`ZH=7#ZuEE^gp%Z36?WsL$V+0wr)Wsb#pz?&cXdf-N{s4|Goe~8&5iFO2LOW)!i zA#CUOCMvE$hzu7+G>v5;hgW->qv6gOV)oHp&vy0N6>3{x?_fveB|re zN)cuS{YBc5p;Sb}S5wtT;15wZ9PUVmKN5mhkVo%D#dX5s!Qup4ggW1K8L}=$KM^*< zYrmR@#aQ43=Uv42-9I=tLA2^wsSc$2+x%K9gxmJG-%w~CrrN3=b1C7|yk)F0jaC3bhR87~!n=}W&#CeplV8L(i55HGS= zDZOKFib#7BqiRJc5m8>w!Agb~j21c$k}+i%V9+Hm>km9qRuL={+d&_1be?|2kbnkI( zsJs3rF)eknj%#TdoG^xZ)M2eL&{z+22gw3M5LHv_Z7bThm_6Uq;7?J_Qe`bAysyob z4dETVMel1j;f|bOie>ca``WEC2Umh;oY2O*i&=en+1zzP3p;HME|UiSTU*;rKw=%s zN_jpDQ!b0+@e0dQCANgsV#j6tmp=Ws*2}$0jQObBsO?GZoI4E?Jzu?tQa{unR+z*7 zWDfjLOGM)WbIWUv{zxluG(xeuPV1CWC;C!4K@UA7hB}7xczl3OzZ?(H$O9{11gB|K#p7`{vSEW7S-&2Zz7`iM3LS8U-q;(c z1xf1C`^_7^(y|?0*dAic1hrGe++!6(k|zWuKY^^)0h^#Of}cF2*}guASO2vZ@+eH) zhXu)~gq6T6X~x$YRuqA*GMwtZ*48qq^c__8jW)Cm5AHTs^hkif9`IBAh^%k4F%mr` z1FlP2$bA>jn}Wu9lR^)EtF?E+9K7pWZEg|6XSKkBbiuor3D%p$Z)K=2@Mu_szvaUa zHSCmm>QI(cyg*yuQq6Z-n&<}?oO+5Wr>)q_a_xdF9UahA+W1oRf_oh~9#t?<3TO>F zOK}E+l>_nA8TV|x80wiN$AElU!lGR1@-xy$KPx|%!BYQMT{i;+gV&No(lSjvxzpR}O^YMD#E z^(0}ln=;JfQ8#)bYB}O}Ky+}P@(sjE8+=P|`evP>^FIlOWoEz9?DwH#MErR=tOjo8eEs!il0*`1Cyk2_^ma3-N_TT* zeBgR1NtAPql0;Z7xqzOsIU(S4T070$ga8Bye>BcXDCv`Q?5J1ZUl9J0^cH}to~>MXs-s0zoDOC;>4(a}8LGBDhx*J{#J18MFu(XR3Y z%}xzKi4>b|eZILYHIVJd;4a0vPmG|Dh<;B8S_gV3OIphm^Osjig zM^Cr~&mF2|BmQVX9nzVtexkBAfpUqIQBUXF1lG7~m`Sb@LL-eH@dSE$_=_=-MF)rh z-;D?8ga>#^Pn{!_+cppqWW%xaX(2lL(XO_E4o|Nj89Fb5Fr_+@NnzaMD#n#3+cG0be$!o`VNzD!ws@8q3{ZHx-F{t6`y20c!FELn z*91ECU?M105qXZ&mE|~7Oc&}-R~)T&^*9{e$S5D0M@Ksarpd{gK~}p!fxEsf#$8X{ z>73HusOYI_bj)Xr&}Ftt2o#C9P!rdu>`(3tHhQ7_?gBu4b`zRSdCkHrhli<)|bU z*Dkh$yCk#6_v3NG>HbK=d8i^%Ws8*6#>KBq&;V+wrWo;A0S}Xz6 zd(-@Eum>Yxm73Mrfpn+LvXb#$D8x)LOZgl+*(30Xo%1^xJsWd6m|J@WHafB-qMv4^ zT-O@n0(vjh930}X+R1I`xPR#jJjw%PoQP>$|DIC)fmc~?HQxOHH1HYK`yuNTA?x7S zo0=QA$%be+)eH>Si(Mg|$qj@uY6aZ-QkWi-@w{V8z?2LZNii}bX<30?SPzns8yHXd zg97Q3d8B#@p;M9XXi<8F z!~M2!0BZ}swU?;YqX@X&OMe=NJ0;1#%->BWVeW zD2tknWE3NaKkuQ2k&NGr3ssY_a!rD9;Jg^gIpi1|Xm5i%BW5`D2TTm-A$xf?c_1^g z#Xv@HC-GYuy^{x$RUrkB1U)$dufh%q^v@A%qp%u9ABn78qX^5~hHYGb%r*|&rpSUPLUgX2I5$8=Cz9ms69Qr34 z2W9;@^YqZb7^j@=U~Sje<)7+?ubEz3MqYe z0P)c9n9W6jK5c;10reC++Xw`bcDyT`ZK7`OQGbC_M+82U^a<75^!Yxb*1Ad3rpN<4A@_6a5puAC-bB36zN*kIz zDzM+3$?Mf3>NvU~M|aWa(SdLmE@u4f%3tYl6|8iYwijpa*vrZq^XLp}1i6roahZh} z7`h`Ojt6A>&_@4=qu$mabs5eVM4#68q>l+aEc-NOP~Dh@K5?L$GBz;j3dwIU-wU=d z;sxtqce>L~t1=zkVW;El{3q8o=GQr)=`DjgXY7~v5k5{Ai37_k{4y(?voZ^XX?S>qdEdz#LS4~((97(|5=FlG!W zOy#R5*rklE=AH=wr=v4Nz21fAVqN>?z(9Yq2S)#ij!z8a1eo5dgj> zVq8Sbl7?~7!_>1lu+3e@mGI_zF=S#MOWaL#rZ}*4fE?1Ztjnf}F;NHGC~cA_li`N+ zL-Pz+Y*7YNw6$%q6*j(=YLc|rdQsi|MiRaMuCUk+5Ek1(c&Hu4os9-tmVZi|IeT(o zsiTNj4(o3f{qQ{Q193^Nf;d>BF+E|rtSAT%@+8?Z=iYpWcQ3vVQejp^FUg-FPCb6{04qb!8e-j->lIOnUNio{VPNOC}2E~P5q1jWh2jb54ePm4yXwI5+ zIyNUzNTXU`(Thr^1ro26eg5(P=(9~jpKOwseLidV`Lyg$CD~ti%jOw@u5{~6Oakr` zyQ|FU4G8PIsd#!|uI$bTU%tE0ua|Zg-6Ff&u|;+lx?gq|4WqlcHg*r-dHaT*@T4gB z#NyB@yL?aK)0g(7u9Q7}wu-G6aR~Oc7c(hNUEG9NwHP5|X$)f4nwajC*_ZDw`j2Ma zfr+p{-OeYH$=P?y?xNSo?n2k2yFT>htUzBkcL#6HxT}F3CzQpayT0_*3%S}1k2q)$ zjKjDpqqy_w=`EW7g?!8k2!d?(uYPNFkcgK=bk#Z)}Ip>uJMVRqow ziL$#s{|By5U#7c|-Q85?Q;-#tW02k5P|2sVyTQz-cHdWu?gp5rI{CXfyd^9o@;nVb zA}lnZNOkPuf7)HmLZgd$w2ME{X%}^&sB{vMMNiY2uKrGLZbzAGrgrmpa(E4%ns=cn zb_Yf($@F5g%1X7k5Zq`#*4@-HFi_g zRl%v`$o3DEUzBG^&-M>nQN!nuOK|>*NK$;XbFYXbCI7eX@W4fliUn@pbUG{aDcQ#JI=MHoKr6)pj4Xyv6CMt_RIaL{Ei z>>PvPl#4L@)8?Ly2%60hEE9vOETZb3{>5%iKvA!`CVL=F=>;avV|U{J(UM;N-jbs& zgKB#D(}GND1ttk&9t;`c%&?^#UJG88VrLoq%~(cfd-*kaR&AA;J$;xH_Nl@bG|un8 z&wZ|gg5m#-YW+C%#I+naEDZ6Q?_w?O;ir^bRIcK=hZuCZ{*X-QU()(q{}7o_KEtgD z|HE#DcP(jVndV1$QOR*HW9JQ>pn)6oYC0P9r`wtPF3Nnwyb$ykzzWD~(0;u&+HS$=kUq~~0`?KA$4;QWM?Y~tfa0&c;Z+};ruzsS|I{n8*-$=P+)9GU-Hfnb9#6e7-p@LKA;K%DjKxwp?mLwW&Wr#d;_)(|e2Me# zl4IF3?LOevax6Q|t1|)%#Xf{JK8DkpO4gL%D0;b{e`JqZK`Z5duI%zY5!F&k+w8S9 zC!@EhB?nYLLOt{Sb5=-tjI78ncgpAV#0U#lJ)WE+upPJGS1yN2*zjE`LV4A8?~8AI zhMw!_!%)X9^UB?kP5GFd7$Vu;6{weB*Gm+6aEa3GOlt_G_V=epI$z;1^%0)d4 zLJuwN9$LyC8X7SMqFyVzUTX7tR)1*0jUD8p5s%%7r+FiY@0MTQ)@~%Nc_T(|)N5zg zYu7x_3Q|2fuxT1VBk6V{9hw)^bJ0kK-AG3BJi~{X*M%&$WF0~qo$PVx+(du9C%*Tv zzav;~!?;*EXtx)w9N49oZgmMPCn47@F+M z;df}uK>tj49m|>D==?zc*X}A|=(BdynF9Y9JMkP94)Q-Q+1vP*&JOb9wM1s`FU{G5 z{Wt)q<eGbOU1yf)ezgJgFfAAc&<&Py8>w!Xe@;;*TenLa ztp@@`HQGn)xLlZ4B=fK1{0?}mEWCktW05dU(>PDR)-;9-^2pS9+|}~;vJWLjQEd@K zJgYR;W;$EspX6OEaKZ@(ek=AyM|A~V93ANtDNH9}x0N5G6WpM-u*GC6^YmE% zvoO*yQ~iy$ju&#CPln#7wiB>4p?oAcdW`l=@DFRX1=LLFd4Wz~OjnO?L2(oP0ak{_|7vVa#uv61ylT6k1mz@@o9Lku{|D|& z206}Lbe;blT(RU12bkk-^rwMUMM~dc&YveHFQ=@HR6QRt?G!ef{6Yuj`_pBP@&KKj z@1L6?E5RNx6SGVVbe@y=n^H-$Z-R~>+bO5&oBW+7rgHZyJW1j#5v5`FVSUgN->uJ? zChT~m-^tDpHG)>w`K*0$H{i}0_692<=U^(z}h%wfNGq#v)pDvwy063fzurZ}xYR$Qj>45W}dUsNA(|`4&pJ#lLCA zIWaS%|E9fSkfQy0kfdgJgd=b=Tj_s~tV$71XNSenC(56&%lC~be@JYWz|_O!p^a7U z-OEgl$Gdr0e!ac!*q`nC$L;#To-qylO=hb9keO!=o4_jgLJ1Aj z`kIP|^~t36i-n-!=0-I`a%U`(PsSqo8g0M35y?klkUT(V@AhwKwS%#|&Bk&cRV``6 z@^Kr>y;OU=dnSFl#6Qf-hi}S$tOH3>BN1wkvX2Uv`iD)ICv&^|uG+2(Lq!DMfDx!I z;%tlLwfvi)~Kv+QS(SyJhD zG~o6w&0pp3bj5otXFAg+40UC6DT{()-f^Zt6rw$dLRtOsOWRkr(d(iOd7aeXrH17)8z5i858_R+g z1d(4pg6c#DF1nOG0Bw$|C_(!40spTn1QqZyqV(6WilmaGZ_8!X@KCK$+ z_}|{WCo(|cHa0+gZGiB|3(x#MGQA@a9lJf1FbC=4yRk@q4`UrFR-3*ncZw)k*K}q- z*Y`+b{uuVwF5Y-cmZ_lnjw6=JjvJsiy4V|97o{>bon!}d&o%E@FOlCvphRrP)-`nI zaPA|cszlHFHd#phR$`&2%5?S@%^OoD+vQF*Z_Fq*YmekEb##$~J-H%3&WSgKp>D6l zReo{%gxPG;<`;8tOf3F4CQ`>2bFyvj7)Ld4<)*v8KaYz<2gg$FTe%yOI8iZd9`?3Z ze6D5F`lGom>=Hw$`e<&~6HB||h$(`& zZ8((4qXlp0Ue|*aT?3bBgtgXzojj~;h?wAUU-(z+qsWOaP`i#CiXcuUZaF# zxwx&zCyq~&kr2wDKTpp=nEX|_?Wyb-=)wgdpsJ4LPV&pq{x4ho*5Ia)p$4dqNt)?_ zAm-abvS-yysm-10l(*ZJUNryR+&NjPyl32kg(c3jGEq5Im3Um(W_Sat2u9NHF;Bmn zdmWZz-n?37@$p`_<+C>TtW!=m0l7eLu;CkArAOIWI=e zlPrV;1gM1JByIU5H`~u3gt~Yh9;ZY$El~Qd%^p^|Y?COAakL$588Tb~I{is*C)uL$ z?WHX$$0_qvF3w^EWX5<}c`A3ITlOC^FPzGSuFWaqNAvjU-12xk?+@neZ*yC~49ytd z2S=>jO;>P2S%iINizixczs93}dTm54FBDrS;ynEhEF8&Mt+tnV)U($i5Anns@{BS< zcLQnJcexwvW=qY~|K&dKxKh>~?SY?6*7`rEf>TGrUuH!loTf{%Sf99}>spt#Rh8T8 zTD{;63#qwj0*T*BbrOaHnmr4sXDH=tZb9%IFEaO2H4BfqwsHzhpVK$kX~RyJQeOX_ zdEKGwDMFL;o_pta*PxK!vnK5HszUz^zab9kJ;`b}I(#;Fo11lf{UDW{%S9|hrjU=S z&*f^#yvSHnFe`qc;+t}EDei~d-Yd`u)WnCpm1x90vWJ*M5#fK&FdK^-yxbuT6pjV| z**hp7ooScveo^^5V#^B}K(R%cDy8AOwziam*Ie#4~`D0yssvA-MhsQwQlyU@RX%egVV`ESK=a@T z(R}n)G~eR#&BG5qan1iOZC<~ovH6@U<RsIiRf}p2Q=+ zU#8WmqSai=dp^5us_PKsym;U1MsP)C{J-hM`P?}fHG)HpW`sc5Qai1R+vD%*(5?1}*McPuFaq(bIk0fJ@;!K)#N?CWcD?eHBq~$9#Rmg(ySW0zjU$2k_N4i4m z+GHt?DTtbY3VZv3#*?A7fS=1XNfmtrrbuUe?+;;}Y*Pw^5ZC&|SimOCZCS(c4R&O) zf5GlRwy%5COmOVBI9H(~E|LuQd$}>4TNhgzbQ|nTm#{74T~3tr|?Y>u06^(5bjBjxX%f~MUt?=OjOdLw0H#f zP{$Uyi6Vh`lvcLTX4(*K0Yn}Fktkj2+?$408z2hU5N$>e4G^W+5N$%a28et%L=k)w z5aGT;BSa5o4SZe|!&ou695*Ri?Te`EQc=d)-J`aiYIjh@i*&*^949&^qY)e(2^1AS z!iZ|=(wyN1V-n~)Vn)L?YHKTP{0dpK+^$&>Q}aXC9Mq{RWL~tq zDbM(~%-eLI%u|h~JnI9Q_ujoEG>^)Vklr>l%89JJ=V7xj8Ucv|B$I_94Uv&jwMX1_ zY{&hH3R~ljh#ZnSs%qUZm8}0zO>3=y_P5n;NS2ItT(~(==K1bzNss2J^kr*plCUcj zw$bKfaC64LfWC_ZJMCQwImH%@dudM_tw45x&{b#KXj9#mu%qDeaj{2x*3Ydg&wG;B z#g(Sqt5!f#m9Ecs$TOvNINZbbNdovB^=zw6mEb5(<4p5=sv9>jNIm|N+lTH;*V?;7 zkZwugG|D`Z^Sta*-$W;l?WQiY%W^m~DHK%5}BNA*MQ;JibLa``ZTbO~YiizDB`rcEN6TgJ)3C z{VEZ2V1hH)x$-QUyR!NtAMY@~o>NG9hcRImchpw8Wz`{@J82>L zzdn%0bwH0_i+Et^m!+3qPssdoA{9hG6r6r*exOgEIZ{!v1$%gm&<^9 zKnDT!yzG_>VGv1*{z(SZGkDAMxeTbsja9aZX$+2jwVB!ww`i;&G@TYa>(BRy#$FEB z_f0``KA|q8M3>O)t{MV%u%LU5QoCtyOUMp=6VsUWSPW$0zEqs0$;J*ukM0(s{zPL* z>P)Kt3rybM>xG(|@FV+=!2GKSnv7?PhIj|EW1Vj1S| zz;2l04g>yutG}YU$vv{W{1ce3v^2;)o9SCqQff5feG{D^R#G=h!_p4Li8?59nzyM753IzIfl_{A68(Ht)g#u zKh^s*1T{oYd(^9TuYFcxnjHFy`uVkYq<@Uj)lA9N7Tf;&`e_=Mul1tm1KRm61}gyf zy7JdJT>aL-qj)>i%QX(l7;Y9wcYDH999a6WG~&35zv*|;(f-;U zd;$=DTzYs|5pkhlAX#~Ulu-yLHKNecslP|#dTVpsdl`rERMWc=hcEiBdxmlFq=YKy zZ0|-K_L@igXxm&8Vx!e15NEQ)Uv@FXdh(?ZD@g+4g{?5*a5UbZN_ZH1Q1LYZIHe5G zTDz-wy}zH941g+jFb&()qBT_e#jrvu9*PCb@`!Q24VMYD$~O9P1dIXIun#E_)?MA8 z^;c-a>4yR>!!0QU+u{|t%PWcf4iyiAPA7AYP>qf`P$MR_btQEiEEYjdjKNh7B!o~{ zAN`eP57zFJIm$$;8?0@T2|P}*tPmpNs-M6>6%%OdaOj{6p3;eC57A~$EM}O7VFCRG znndeT;ZP=EMbOnH2fPF?18t_n1S;l% z5!xC%(T&E1v`zy;uxh9(Vxb5(@yHDDKQU;||>(myn% z5t3)?Xt5({;PWw!Sbjvy#x!F2&sZ$GHDV#DHuNGaZEafg$y6we#WG1$wlfNvVQES% z`OL^Fl2{fAZg-87SaPChbTce~JGZ^H9Nv;sQz~bNpBL;#&vT(Ao5BKXOe7{rG6s>)(m$^~>lTDsVnGQFk zvEgW_uBXtlNkUGDantL7(M)#<&%$Df3@7yQF~}$%HbX|I-dBMFvfQv3jFfjSixJ*Y zXu_!CjY~0t*`^62<$#S*wwPbh>GF6+De`hUG{a60Z^B49V%AL6Z~!UMP$_k~w$LW# zL)38=E~%F!iOG;eGiG5oAqlsUEE7&&)w5tb=P$-)`K4|aZv0E?Z!+i4(BRC+4I3wA z!&PFG^jl&YMu;qKI8SgCf)6w`%wG_Ql)s3E{e4*oFK~@ip*G`%5^RaQ{LQrhwoX@R zyLd&W56-8|tFafT=J_?sw5}15)bL2nr3=@B17z!ne_sOW&I#iRnqQ(J3Kp+TS+unT zI|I(K3aDz1wkas<41#s{%%w0K9M~L&iu@QD^tLt(7B_xv3=Fs-)dT|=tO*9CJ_ZIO zo?(yxDF_U7o%UUZ#P4Oe>EXRxm^cxsM_#)^;PeI80~d@t_DpzkNF-9lKpN?E{CX_0 zOt+#_R8y*D%fvy1R=*JwQs#U_Crh;sPUQnSU)u1o;soX0pnWa7wH~;%Tct*JnDKj1Ot%#;h;B0+yJC7h_-DLgf{khFJnh4bDwfRGL1RkB zyh?_l0Fhfc4n~EUFkc&jfR2K~20V_1d#~_qWQt!8mmh>qFpF)|p zgEUMCb$<*Y6!_gV62g@pLx`fx7(!IEV?tQ0-rgn&5qeG%BKnsmLg;^JP6!3DN(CYG zX92VTPCJB5PFWs)wOaEX~>)5UmI(k1$vq)SN76sC*y zQ6pVsAEk|S@pR#Mkk-|g5Qj_Zb1o*1zJ+SMcwQ=V86*f($Vvr;T7hX=G1KTQLHd|g z_e1;Z!W2O;PNtNe14_j+^YC|A$ZMB3Fpu#TEn5jn-M$DDs6J6l@ClNGeq7N&sn838 zQtilRXvwzY7oy1tHaZpt8%d(Hp}b145hse$X_o;u;zWf2u$66RnJ38=dPHai=wtjKIqCK==p&D5XI)GmY%DIKPsK|y^f~xi41HX%>GT>f5z|NikUFk~Qpxl|JV7i+<&rci zLRbpc8M+RvqwsPxmx|Y6IdbuGggbHTz%`t3L3LUOuHi%x&gLCBk>KTMucQhhA~99M zKQ>WCdB2e=viVtLZ4}GVRgF|>qwZt5!}-P(Dq9a}$P8or;bMX)31FBeg5-%=rT2;@ zh+;^B;9@{Cf>^)D5X7hu1i4x+OLaV}iX_)ORn@>Xm;)D)1{~i+8kakUG(|0ANK+BV zq^afwYPKXzXsaX*F7pe9QF!}wUvtvH%*&+Ff4V$rte+)mbe>Dl{kCXb&8ZJ+W!Rc< z=%j1SqY(`;StUbsHH$ZC1#rM-_Asc5a2P0QOxPiR;3{z7x>^12p0snWQ*EC9nKgDf zMo%LDeY$`O_Q?M!Hu1QLo;TW^TJy|(4>xwI93*s_ZC>{$#QAD~L-t%Rz%T~FKzaF| zIo}$Ee7k3MU~(18o@JtlQXfUMJC>3d!m`J-n_9^n%`1QXqQtxwaB3rGqH?_3GE*v+8r%;WEKcXz7El+A%hAf!m311C!n+P)ua~prN63n_M z#nELw(_|a<+zAbtv*3wc^*kn=%vnc^c51_t8JMCi@EL=>Zl{*tLw?vGVvJx9mLYu( zjAWS(b+prnX9gTi;25&e)4wyf{8^xPN*F6E2AgM})wbE_8K)UNzan7L@3qkz4)ls_ z^bkpfLrI;Mc`CxkKdEJB$O?BgLzBPZHZRchntf|DpCh@B2LsXGKH5jQJ2As0DR62e z@RhkgQqA+gS3(DMssUg5;U|fox>`C5Sa-{GxFLPli+i+N97C>(@Cy!b$v`+z(ixq5 z;Pjz-9FF*Ta6a*JbFP#2?}xm}lixl>6H6UIu4G+%X{CzSWTlF~HC3wkn-Ef+D7sfG zbQiPKevA@c#J*kOz7cJFGRzG3y{L7RU!Z7Kzo>m|Xa7d4O;|{Ev29gW$*nj8Q?#+! zR-7q>==Z!8=Y$oGO*}+r_d&$#48VL^vcD044=w@VJxYD45r8)&0C@}mj10oM@eej; z&uRuhEn{=N?2{9CNQy3+*yO&}ZI2B!>`kzVArLk$H1%wZ zjp;co&2Wu9TfXK!hktI~v(@v`o;+r1a{CS|WGdh?uKM(YlHyZSNXvXJ(`ypEBpa-x=w{Zfi~*DX!cKmp-%Omw3UC~rISAe-mxvcb2l4BUV3aszZRSGa}ucT=RnJL z1{PqQ?Fo@Y-6p>B5ykxy7}UoY1}`1Bm)W6UYI$I0Waah7dtF`Og4SD{=g2dGdg0V- zAr|H@hyqhD)FY$6c+YMi9seaTt&MnZ#lTR4Yk7FFy(qi@c=gdV`$C{Y=kUNti*-sQ z^uzCc&+c%Lpzo{daoT~&@qmhJR2Kq&bdHRedA|nkauu@+|+}?6ya_#76LL(D+45n(YVY% zE9Aq2H|yJ*W1y^oyGJ|M;5enPnhjcP!wwJ5O5zTNq?1}P2oXnCCbg^>>~KWZz4e=L zW+D}s9f+Qbq`*ZWbPjeDq+f|{+`TC55CBJ7gr{vf5S%I9s;oa!M@O(vw~^;#5W1QK zVwLI~MkrG-pLH#jIf6Gyx+`tXI!EwzHy>gV;*sI|XG`zx;!Z=oG*Atr=(xA?y( zQT)#$Xfyh)jGrcgAfR2)0tU!kpsuP8ti1e$oVTIhOY*zw^v5VRVmFiFaWd`ZrVeN@~c=xf>kd{Z0HURSpW_V&oew=`u~ zuhP*L!Lcp-BffM)hx&f94it1W^_IcOE~j-Cx_Lfabs6iWRJ}ew&HSKs@Va=XzBVQc zFWGWddHbNl=~P>o=MNP^JF~>}QC>G|I|grbIE`m%*PDgeeQQ|Q9u$)-l4wsfE@?dl zuZINT!XAP59>O`m#f4kQrmD`t{!U~2<^ftEEqSZ3g}YYB0P8n#b88?KcL}Dsr-~sD zzd|(|irSLVB{S?o?-c{1f8v1;W8j_YE7UPFc+OoV240zOw(lB*+G?~A zP3|*Gx&}9WA3{_<2nh{ui&;vx!qPmjps8zVdylS!}3PN%Luuv>gjTJH-Mw5k%2>$izZ!*EsZOvin}KszYR z0;tL`+}cW@VKc7FsrVRb_x13aP4cqR}pC(RBsi`2|e`ptbVQSZ#WcUo38OL7?k6gS7xRJ#k3`s`@xRlpDOyEg(z`JxJ}f;CK%c%F;1XidUekhNjXI z4I(i6O0c86n8O35{AqW5r6aPrzv9KcMUUI9Jf#-|9dtAh%(kD&QfODd;85xx4E9?Q z8o{qK>j7hIl|9VNbT>ZfM+yx{ZBj4A=D zbuUlCWP1{FD~K0V-zS*U**F#R|UZ+Bx27+g5SYFMg1%tpdpAQUXI-^ffLIH^Q#%(58D;uY5 ztk&Qe!$HAE+v!+;q5BBB3EhE*OPP%jjKPuZlm3PCq1 zK_}9l!r;g@)(5auxrJ6^kKU_h%8+1xC=R=5#L!@%&5ohX>1RAZD~AUE>l}%AGgk!h z%8F%}al?WyINKTTMzGp9Cx-qGm7FRJT`?QdF%i-STq2|>OtC_WKU2aOA>zio z>4|rUGqgnhUc&M>g5%9E?fNhe+El9JQSHTAAm}0CQy%AX@#??%Qc|+G2g(I4+*x}* z2V(s~VWOA8)~BJWi^(XNV6eICLLp25p;5ub&iFr?2Sx=Sfz?WMqtBv}F~OUi`dK}l@CImat{0YG}&L5`HvI)WKog;6dI(!T=G>TH164xC!jGgf1v-v`SyEZiR zIP4#UI?1#!wo>jyD4-+9nI#j0k2~7v4>R+KsmSzEmQ%@*A&BF}68~o!I0;LQMEE#m z9>mkWhiakG9@?{cakcwsbSqpt2l!!{9!}K7=#%xl}zF zKv{J(@b#RHc6a+JwX{!XesE7WMLe+$GDCSzEcG`@2(7U)icuMZdyNn&LdCM%EfP_T zmOB;P>z^82(<2JCW>07hf-}h1r}rXV7;Wp_0gQ&=c31P)r&(asz=IJRmCL<8&H2xH z8uOpl1qU^~KF#^N#Ou?W~YY!aSc({y&AEpDq&2riPA@s8ks} zDtPx`U`!|2%=!TY*}(goQn3d0LT zU%yBb=FFKvpcr$Kx@ES+AFwR^dY6P*(XwQgKNf5OvOf^a& zfU;V>&s;et_+Wz5*hTGcL{+6b)!rDK98mA(0+rzF{>1WVz@`6j~(Mw?q)! z7(m7Ig4Z~s2h5sz!6ZjJs}nOLU(G}z<`Zn!Yv+UCz;~$!a2rZ=uSO@!UP4ovdcl6a z?y2GFSyenYw|KcAo}v=JmEq#1g5u4`@A5)!Zr-Y=)SRqP1}Bs==pUv4OhPfoWC6T3 zlarP0zEf<%T&K;dn}d^8r`3u+y*+rF(@LNzW#ZRCuk-KE)Ni3ke{XJIDE2PKtLFJd z!Ovk9siwNSf=k`3S6d%b$=$(DS{ZZK5}Xz|N-N{w;3Z~;p2stetwMrSEGpZcil?DP zc^Pg_>Kp0k-NE5)qPKw8VAuE#zHZ{61-6OICBeY(=(`jGuZF{?L}(w}H*g9Dh^Tu% z6TFGl#6gDW+S=vn2j3H@R#}DRD7Ve&%?G*S5kI+VNzms+6pI5(f_;XEZm`??;G*`h zax`o2@&BW}xsui9dV%yR`#lzT6Vj#l{xJ{?BlIrdO2I{qxa&OQ#HiT!T z9R0KU;cp=R3b*z5qEAg zK8oj`W9I!oc-}t?di{zWkkbV`VaZUucL}Lfc^8cYM^uhn<-HqexBITFe%S60d`HPD z{8(=Lu~vBEZ~PZ_;jr#7W13X^U_lzqSsrY0b7hKb;83|2TOyBp)tSpT@cHqk28`#i z?Q#Mjm)IG3D?~(S*BtwIuKX<;Eq^P<$lrt0sV1&>x?Av}8cwFO%Y{J&HpLaecE0Eg zs9*LpvAj>XHxBe>3wv=07o=<#Ql3IeJ2F-TJ9M!AG9VpVSzO|Vh`6h*HcThwA-sLk z8wa60-%{!1ieTVIHJOLJGMpfOJ*&bg;*bO?7Pd${S*AmkgfUP^29eeSv8*X>P1>xv zy*WF+l*YhgG43&))w| zyUK$dS_+qja)dkMh@5^pULHhHDn?`h6+f6WvV-{Fn1{L1B+6v|jZ&0d#rFJCn4+?K zxp^iW`i`pI*^BAEir@xkQ88`J$-OWx5B#DA>y9#b0k4=mVR?SH9`XvngKzu`tWm9w<`D? z78$c@b?^hce8nx_LS^fM5Yr6CTsp80Mf6d$V0{qR9k@+&umKhpV?Qm~5S%1~l;d&L z+6}=z?ers!QdH;|OaSXyYX3m+ai=n!4m=RN->E!8`X7RL{-iz4{zI^`v-MyEdX6Wl zL^-u}?2k|*zX7G=?0BccH&sY%KA>b>#* z(e?FlQ5E0+cQ4#sL{wyjRa8V45J}y8FXE!9UDNfUtgu4Oe87Cj%n~ijjN~dVK7@rK z94jp}DJv_?bj_@;>6(=l`N^`fvdpqRR@g_)%JTP~nag9}-ygh|J9FmDnKNh3oS8Xu z#;3&v_uvB7P`Ae~c}7CIqN38N>P@XHRS!VWpJ&(jw%7>%ra6~;v*^J`d`T{GY}AHo z9>MZ9pGTC~Mi(yke&RfZp&EwMW;y1X@WZ68#Y%=f_2-Bz$0MaA2%AU+YwHQKKBQiQ zz1@oz@REyhgHQ2Fdm~|lMtXQ!@Bz?=(yHW@wlzst3fZ>ozte+@*nPTkc73!t{C&-- zkVZjCvYV2aW}sLO4fb{w6)Fo_00!uEg|Cy%;WwJ_(JG;VS9rU22AwdorrX75pm>zs z(qWWe>BC#)ybIv^LFg%i%gsG_nA-QKjdT+oBHx!bSY=bNiF9ZkTbs(Ex^=!GvMuhn zQ}QavKF1{Wr5hjjO;c98v38@fJgO@rV9H#T=X-2CK z)0{ZyQTfRHmI)(Y=`dk5SekW!R;)*z#!%Y2-uDICvSNd;r+5X*>Oi|T_@EdyN3EvJI8mAObHgKViN}u%oY_}?r%ql1t zaRk$wHdkR|AeV2g9uC!3`R2=+N`);G72t7u;_WvUlw-dN@)Cm@4~iOmd+Ybk}pf?`7#zs(KzgEe#!fp4qxMZ!%x>!J|VINeM;P_;9H097HkOd<*Qc4gK4I zNcu3ed7JOLM90d|+4p>{9gc;S@B6%tdqS!2`x0T`y$~`!@Ofm%P#Ry0Z3s>t9#-NA zVmYl}(biftl;>cp=X9+vtv~;;aF7P;9p@5IIJfY9Shm;7OG%$#0HxzrEUah@&b}M_ zus8ZhrB$`Q&fNrJ>`Wl`#=vc^5pX+-=th>7_ciccE7F1w z&Ap5@|E;r#&p~2rdbmBShMf`Bca89Ra>!cG~@v`Z2?I82E;WwCshf-UPby zV_$6B_z!_}kd1Ucl``NX?*Zumk#_QSJSd5@ii1Gv7ir22I?IuUfwZqkOPfp?M*tW9 z7VxPeZO3gik)<7Z1NeFih9N>^8B42p4frwzTtzPJXK8u6fUk$=2xDy6PZv189l+-m zaOcKSuTL1hZNQf-@CDjXK1-{35%{_axCO&1kD`6geS-GoJrA6TcHLf9cLIIIGUB%Y zG2B^M@8rS#=M!IdcOI+x$Yx-7+a*qt`e}Ve#YR*SD@p|W()5OmJUq-SwGkOdhSIu* zjQGbCvhgy4npKkD0%k+%l(S|3X0 zHqSdW>!|NOuNXOHO-2r;Bm0y>;%W!i83W!l>iL~-lgPX=mEhz#H`|lv9K8B?c`#tat6=R#Lux*37lyTWMNnFbL@2_^AdAHeZTOv zcR2Z%Npo-ZCbZ^+SSjAVn{m{-9IjC-j``Zk=)ZNxaIz;LuNEeh0CmGAg7)A!)+j3b z($~L7EH^jZe2G|hp3NQaH5fN+p(^n?riSXi#C&4)!Wv8KMaEY?r;LYQMtCuYEbM6>pl_%8UN8fD@*Ktnh3|jV+uTnN9QkVb2RI|p? z-T%ezYW0_tf0_w!8}w^?ie>$ZX@2c#U$%?0-?+Z=YiMv@g_%gFPx}_JleAesW3RgU z9jf}-m+q_>00~6lUwjGjkuXD;K!5)1iy)=B;}>7L9IsO@`>xnSbMT#X zq&LJY5>vJeyCfNQiHrqYvL}rXLEN|lOk71zPMO3hn+jX7iqxM`!9TzFZnsIyp!}gQ z4+M>MRI_+kC#wF{S0=KhZZxpYcR&ulOOa=M)pnUkZ0(^74uuY#@y&L`Ro}r6)noDz ze;3?S0&{5O|6m1JeEoGLE&QKvl8x>p9c#$3au6s9(|=&H+nJA8D_lPMQQxyTM@_rQ zja8vYv(!-OSzjLFWibJ@ELM49w6u~PBb2vF2Gn-gG2ZjOtL5+lDmd>OE>}EHyUxR! ztbqFl-26oQkE8u(DrMYQ%{_yKis+%I@zx)@=s1r|b!TYn@4P|nS~RF_(*}J<heLDzWKEHHQ*Pmvx8s#dmo;xs#6{MgPLz9*wFkGk zF0%H(*QTL8OIdp;f1CGma{ukSvxmTm2XN~r;WI@DCDFD)o$zX`wxKP5!#t9ea77n& zwK)7Wf2yca7qN|vUJkWd5Qklp+9S0_ZuxO;OvUVTnBs;M+V&2k*WQ+nzY$0wm=kD4ZTt6`-L*w&n~PB4z9 z!Z`90Pq*%+>7CR+T;k(anx3exlBFql@mrndD5tt~HJes;RyEnUKD4K^`m#d~|4Id2 z)y1-jP0Ft7Oxer`jZab^j&gh+I+d=D!sz9Z(C`#-hKd-Fu(&c++`Q!jehe+^sUC6F zvJd0FCOO6sT-jE;iX1p7HYqbGv_Dh*+2P{@okh>(&A^r(8(u~sxAFM@CRPR5Y8DD% z5gqTPZjyshp=G^QCp?sHpi-YYplwAW#_vGSkq|jHw zVk31?)dB4*+5Li^Mu!HftD*zv#W(h5^9QMEBG#ZeoRUAs9KzXVwWTeC)LWvJ z{|d<9+tgt&l!S7L1`bvS%XvO39IW<{^Lo)%{@as|4OaU(k1(2@WDZsn6N2A>!;x4D zM0!rL;c?^}o@{)pIwa9}6I1s0pOU`&QuTUQqR2f~x%*LrQPtrgGsv=lMdkpm! zIRFEGhy;3yW2Fr?1N#Px--3~uNAtk@g14T}`? ze+4rX0{1tEvsO^@mFfdFUoKFNGj(2%8oufA2Df}nrUIpVn^`_(EX}-`YMrTFUHn5j z3fk2rc0<0SQ$y8J*&GcdR;k4S4h{$lkvAh!erj(!XDn3>f#8&JOo$dUT3xCu?-65diP9dM ze{geT%rmMuyA_-`@w{+sV;&y7D!anlfz)f&wp4PBnlGC^Qah*msoS+`5zcf%RoALR zB1MfjDPg3i@B#iRbW&WC-MlEio3{d^X2r-6q2wFX84)&}yQy@ninq)7;M_rb#zLT_ zrS#ocb!LLqw}JEg9FWg(ohW~tnv!l+xSbXbMA@P7lSiTU@cZ={w&z^F3_GnHpS4+Z zhskNWgZ7V8H`v5J#@Q1sa;9P%ntt6sBA(Wd$INK{Nf|e(!=v{-OHX}xsd)R)9(18g zYMx5~D|BPm)Qw)=hvvPF1D!1n?9~Maw636zNvSvhLAz2@ zac!G-hpS2781IucRlQSwYbMpCrS7mH&eELp)GzJIzN6e8sqq34F1FTmOz%X&9;plM zl$$9sBNgG#8EW$n8lRDhXU6!)drb-=uFCisDqjEP6kB452#Qz2YN>A-ZjbT7!?9U~ zba1Bnm>kR%?&;YQ9;uf0XN zf|%^)@cSSQrOS&wkIwu)irztkeXjOQmR1Kl{~L4_kkg%$nX&Z;I2Gaf3k5e*ao z**Pr$N_l>QlH*p&fJlPRBFhuf;q+x~RT_ z1&tL5fI<$CsK7f^Wi84Qh^i6lBv!PX!x@V>T!MmwD}!-J6L5LJXUm-lP1$4uq* ze`~Fibq!jFBQ*`1s$79A@N0{F5u_(tvGc2cZjnEbYVT4LCd7Y*l|mCDqyZdnqH?8M zD5+ewvx;-->;@$y>i2WFw#qO&|Hc;i*<{=e{CU7{D_k5dNN zI>}aU=RR%FNuquP9tHlQ>~|Y_f<*bA9L}la*q!lCi~Jro zop!!*utk0v&%az&1_%VfmKAt8Ky-Zt*)1#RPUZqEI%eQDLQ|C^b>rpYm}=rGCtKi; zNBO2I2L?~=0=0XQ$`0*C`fARdb_4zwmmj8q2ld@24->(8hG}Ri? z?>2IrDD!0|4D?ud0^pBruyd0Rue6U|s3ywha+*fEohmElBN z$2r~@CE3IC^X_Yr{}s=yYS@O(DYw5nniwibA1%;YMm0gu?A;bPJ%pEa00IhfI3Zre~0CIxS)|me`&reVy-K`2(g^@PllelVVfHT529;e99p4dEJ zHui<4->>#|_{!Pcs(qCn{u{AQ{0@Co{1!hZe)m0Y=WhsEg=~kFFH2a|Qtn>EmoiQ~ z#h%uY4i&0x=dQ7@&!&LC()uE{kZnyFrrQ5%zB-Ve#@vC)ku4pu;^1Oz zIPut7!gghW18%VncL_`9D~YGr1M+}PU}gBKMZiZOHitSm&U(zPNWIGy)5c>K(M40e zK2iE(yRz8XU(@NOYX2!h_#y0|2n*Imiloo+tPv;* zO6*1<$HHNyd$FUCRvxUl#Jm;Vk@-^bo@E$Be9bk#IW=(KSyrrGpJ3K*4?f?58so#z z>0%W(r>vcHcTnw@Xl!TCy@H4qO|`a#_6N~>okjJ7uodPK3~XTD28vm(cK34tqknxS zcL3upHy_2ba=o{s9a#$A6UEg!cf#fMCTc&LzFh5-V6DZvP*klzDTs3Av}L*aXPnUu z?aFH8vJ@G5Wrf<_Cdq2oND?!Axmqfq<15upmvfR#*lhJ3j;jP5z?y@Wf+UawQkZ_? zWK|BTC#x0pU8SaV7T9JrNPyCSU?$zYO1-uyxP+jv;5fUi9EKuQ@vS7hqX8x746GKj zI5sG1`Tks%8n{^ddTJ_K_IN7wTL@U=Mv08v`{pm}NQWvY5iwM$!u`voaDR~DttEmQ3SJMJ!m}vWKBm_G4*;reWM`7`hC0dAOwk#Qs3o>xRd*Yinttn zB;ei7t?4g_CYnnr_JwreLv9q2QIj4|H@%RaCcNyfKjAwRKIcY z9x%sK%}eR&!u34QMzKlFuye;ya!q=55jv&Z36F4Y`k~V;ZYJ6w51jDjyUzuh_WTuAqlq z!CL~55rWx?ZJP-K=LzJ&gT#f&+AF@5-S)R-f4@hZu;BY#xOn9TyDRu9yl6AL*g5R{ zvC*5>KZs3WA-0)J&Jt;IsoKs?=|OjwstJtROgA(2KIECmX^*`K2%>=nhjZNQP`S=XUWu81synrR3FCi2`AI~ z9iCC?DYWWg^#+%yd<=c}u)08ez_%d3Osx>LniwF`utu58rIF<-Uf5-0 z+}uuE%hgxCyr6{p+Kz~6C0jGy%93d4KLvBQVzbFbE7r2P2_vW}t!8oP=vvj`5a^6D zI$ojnwyR!E9V*qE?2qMiccuDHQGiKRII3P)_~a)9=0y+B3;xqWqF+FT*v6BFQ7)I- zzZe|!>hHvUOO!vkM4LQspvZ%_3C|0_CWJ)uJn3?lR|Jv9yeA~J9CM?PR_PhLlEI=9 z^Be<)t_3kIVU5kA66G(7<+J%&@f|#EfB(<^wu!)@HdC8|K!?sE*X(r(1v{BeZHB<` z4-=8Rs@0is(io5;RFvp{T!yU1bZfk{U0EikTc#*QhrL+&G|ne@d1DyudPYsA%}=ZC zMT%u$q^OB;686}dVN9k|Pcw{h0^)Fni={(OCX>XwX`Edy zOO&&26#2nx$twWz?1U-AiBaGQ*wAllD_>L}k|kV1e^DLOSrGpwyT99DUnO&G(~VBO zh%atBui8J93YM1Bvh)a^Y4d*!KZ>+p1dzoFDs?KpBVkI;(k zDlP~erajx$Yh|1@#Jr-eij(p|>;t^9oLFmEXv-_=V25nJM5lJB{bXq?CGW&~&UlUn z?!>XG@eIw`iGxh(DXQ72!mWG*MTOK!ojDa&Hrz)#aw?d0E!a~@W(aN(901pXt3qmG zKjRTNGu*pfsetuWjkz3yJ)tig8hBHDXbOC(|Apvbste&Lm3hMMQty$?Ag$O1iZH|P z+NBPUGdneJit!J{zN$`j#qu7%2l0s1ZGud^;Mag1<|YTQZlhtl)$Uh_b|_vIgBaZm zz;-YoTiHM}AV(lO;BZ$C1nKpLV?F7HOq+MBnX)vMYIj4VtjTnCH|#`ZdA-nc8^4MT z2&uOxjVsy021Ux#&CBco@BpbCZV`iny|;kaZ%JSwAAAKo?=_JZykF!6Sx;gIfe*M> zSsrv_5f;I=a^%;#d1jhj$-SZy>n;Ht1TigP%@k2d;6AEjWzG5GJ3QO|o@amCM6hRE zFdzki+uRPvZ`60MIyC+pbdS(LLM{#blb_!h

    >SQjjtmxebqJ**-^ zjF}obctFKP?xC$Ic|)Ktl^w*HSNOzs<#{P$H;$57*$2ZXcfO-0$Z-;86Z9W3&X4QL$$XXJSh$ZAIpl| zEb#(Sfon*uRnNGNGZLj+DdQvPi)?T%JFp~F_7U`^Y#t_Db{IsD{yfZ0Q6IziY+rz0 z`53)C)S#Fn>KGSqhx8b`&zncD9#L~did9CnUk>U|+9&FLa_~pm`iVMQ#%1M>pQ_i( z2GN{Pfddb`?`OY8DRnu@zDwwC_G>JmLq~D@vhEzSjSE8^KU4cTiURM5c81@90f^a& zxuh6jocRADyu1Rx@Qs=y+~W%lQ5Kwp+5chYfo}h=;D1B5;s47f4ckNPC%{WKJRGKA zm?ty*)^2zfoZ|IHC=2#b?dK{SQf~#4Se~fN*h!IJAT4h?DrqCq0xwezON*Zhq^(3+ zu!fa|mva|*IY+_EIf}_Bd~YU!2&aGvzerWAT*U<7kFe98j&x2pw2)d7RkGIZP zfYyC%a|5p0md%+U-VXm-O-c+t&N&gwIAPA=w@4Tc<=mb0%Ga#X>_xK(j#sIkL#J3; zd;)01gu#2~TIzCKoi9rdQrU6XcreScbym(+H4>ke5PxdkfY}b5rq-aDT5F#+8R1B7{@?hnGAFEN}Qt zxWw6$x_paz1J^ZN>U1(53?D-yzs25I@GyP+t=g}xGN(KO7j_t*Rs=>+#}iol*0Moi z_TTxPI!X2>v#mGjwZ`Lk){1&Ja+U{)HNS^$FndtVf#Fc;->ZWhcCo6)VoPEgiq*MT zu~`&*3X}TVe~@~LId(?Su~W>O@c@}WV*Du=Xv>e7Q5T$}kAGBOcg6C$?xS@-!8qj~ z)?IY;C-p_y%%c_mRbOy%N{yF815c}0VuK6n@@L>T0->s(K~WFUDu_d}G%fN~@fIpr zR-6r`%yu<}Du7J?if%I>rG>x3i)+SO+W#v&GpyCrw@$q*eq1^3F`kHRRmVJJMei#Z zxpiu0oU|O{@n<+~;Q}TfKYpsIQ@eUOt%wuT;CJ^gPJB*vb(lf;t?T2gyQTZ7_V2Xe ziR^#l9!vqS@9aHVk-vb{f6~&O=WyqG=zNO3QG+sKbxM~g|2K7%>jcZ$cPrKWhBips z)@og7?c((IcKQ^m>7A28(dX0LK8f|U@fvH^v}o+q;BhLd<@Mghw)jQtC&nEvhT~}T z`Lra|i!vX>Av(=Z|M{QlkxO>c>HonZtH3+kXVvcR841wz*gFqA-D<~X|LyQz)Kd9p7swo3j`G@gK?9n2p4e9B*84 zw-|{Ao>RMDE@b^75EBW5NV(O-(F1Q~xI(ltP%c^-SSMP^)H|P)5OZ!tdhg3P-DU~z zAZH|Q`}2;#21?7$F}!4*S5p$LC$T95t6X9{0zyIl67fK5=ik*nzB(3Q5Rq2@ z-R&^cT4J_5O}c%p=yuPJUh$z*zpIDw6nq<4OJYIH`Dgw{hyH*N3Ne~PUH-%hl{dqB zkOfZZKzlst6X@`tYCK~6zPij|3*4Wug~TqT5c02SWXJSXP96$zVMD>2{5-g^`3ftE zy9sdWT7vU#qg4}3KY$>y#UwBt!VTkSD*IdQKwbV)*SL7=t!V=1g^TLaIP0SpZP-br zf2$P&5)Yn(?2aMhA9Xl(47UMPtP+K|RN&oH7^ci%y`%Zh6S4pJg><~Y#(?()oIz4IJ;wUW#KC0uKt`wcN3vaz@ ziHXwn|GHx@^82wn_E?|eO^_mAPd{t05-26cy^`=s_KT1vtIOd!#P8TAbESYW!uHxw z3GXt{_Sd^4KjPyI4T8s-LsJx`)Co%!lcEPtzpiWZRa4nu* zb!xG$9b9E!gsZUD)jfl8Ysc*Xb=cfGUg^?Ok_>-yiITcBN>pIAxVz5@!`4bc`?Q?U zdY6`nA(O-;o_Ssh-dHjnjMBQgEIyGG(dj5K-jFD!m9|(mdQfRAZIVl36TWqx>RM?% z?KeNKrQ~SsfNXwCr=qnx+nQg%hWm+&iZke<>8-VX{S3UoHRV^&x$hY_3&ax8TqwT7 z_22jMLCDBC&h=mx)wb4lxM~=Str{wg(XNyOh&U0W-6m?bR5IEiAc8RM7SOCVAR`R_ z)wWu{1oJsmc|la6jI>vySBnQrx3tynL<~Xd*iOR|c0J{`(-7t(fePDcc%+ke=>v4I z9h2oUij37ZMTg@!rq+RYs)^Nx*g&)CLae3 zqGRo~Gp>Ey44B5ufB+vWrEiukCv4T*b?~u-I${lp7BN|e}feI^c)!@9{NyEP2IkGx|OvFw(-bq`W8Ms?? zleF4%l1WN6bAn!ow@JOyr8m znSYxzXnl%yRigPdn>(|VJZKYki~yA;2>q(ktBvtgF%C*NN@`lx8c%ftGOp>&0gc01 z!9}o3?elR__#>+IYGaGSe^K}gwqx~AIolB8b3aZugG{R^i6T#7d1xye1BOrJA=axX zcfK*t>@8Fdwv$Dd{3yCCcwF$s_{q-4Am)7e!PAZ*QE=bCj3Y;I`Sy78_U8;OJI)vf z=qBut22$Ui+O>(wd*y9vuqMDP!-7Pxa|e!1dY;zz)UI}1MW=c)9krRFGPPA04nQMp z713}EhfM82oTWEUH$7B%nU>~)km1Fs=V{Aj7&A}@hb{xo9@McH!?`4s(@SgRDB@Iy zpS4-AwF&FKwpn-3W*y6`XWf@J>kioEHaF(6V=I2v*u!QG*{s9O49=N#_IEk^?u&k? z2Pm}xDs2Syyf60%)~>em*OJ;VV-VdpFr$|c8FmZbK7A65IYoO0W{ed^+&C&r)8@w+ z=KwPpWY&+3&uRUjjBf-2>typx^IeMR!89N1TXP@+WMq6^1!H3-=T zn^PqsPholWoO;~m)H1u=Esc3_RS;)bgNavU<#~=Uy$~ENj)ho!Kl_Xe`5iDz+~DCv z1h26HZlv6&2PM<45gFImgJ&O#uw7YP#$bcVdM4CmWX4iC^rx!bD|^cL0GkgOVM_7= zhwHz+uF1dybv*Nf%D&nv*$CtQNybN_fN?|f0#Z(><8>K*V(5&CnFj+F5z%wEL3T?LxsVKORHiDixpO#JPKy8VD#R0*tff}MkJxNi6w7(p? z@Z6|&9gX`I7d+P)+I=ojJz@zD(f+~KCxTUt({B@O!&!gfIK8{g!?9E|6f>aqgBaCJD5-vNM`nJ{?vy=V&$Uqwq0;gC2JwL{D)lCPUTfY* zmJbmddr{rZx`#dtXjjM)@QE0XImXBkHQ}lfr`38Vq)yNy9Q5P}t(z>xlQlxCWR6Xz zZ`Np8kRzDjM08~2?zvNx?X$QX-z23MyHhx zg;kM!wZD~}JD$|5{XOWzae8~Q{yRMSN^W#PKQJ~auzI+vJ!f}PmfcA>y+9{%{L&af zLHK_*dB3q8ou}pEfH2(t#`cbU;EPaho+dlweV383qE`;CjcILMHO%UMCyn3rZ1 z9UZIT5aMxC$Ke;pmn+6;eWJrBI4#cbr(}&|a1YUiaT>OwSJLS5TA!5Qry?I7BCyP0 zfwgDf<%;r&NLSv)y)anBl1azMYcsD8ykX;egKeOoJ-9i`;IT=~+UyLx?p9Q!OA#VH z{I(4byUJK7 ziCCX*&EQUw9Ti-fmRfnL8JntyxSdr^U`#yyHdRZwK70i~8)_&kiMt50;uPhAgInZ_ zI|xo}n{mA72DQkaLI9jcnH&Bi!;fnsK&zpA*&-I}(}gfK}@z}lWE`f$ zj!xgI4NnSw3wi2<2y?Kj&a{Q8*@|27qIXwP?kq6ZSWa_hf!WGQ+Byq(If1x2Kl(O? z_jjtgO-o4#zT?JT70hEGS%T-Uc->AqdYd*lQ;K4ZaVy|DM{J$O0pkF+w*^={Sb}uX zXuP2^8`Fd2!R0iqUuO7C2%}PtyOZ9?ZEXo$ghSsO|E|Y6i}xTk1Z&^Ta5ksGtfRiS zYdDK8rRldrJ6Rvo{@bAfu{bN7gC(wbGjkzT%|WKLxAG3HU!sWtk}r9s&DeTKg~{)5 ziYV&V9h8gwTg+^}oq>F}(!p*6781M-Ru*d~cAwW_->V&8jF@~9M(9^I_<}1Lf4Btl z*~#jM#i=D$HQ)n>wc1nJTmG)3+^NlS@e~}c-hHQ*she;9TP&o_C!&-;#no`kGeNcy z)4_2z$YxY z8u$c{&jvp2pk)iN_O`UjCw#pq`5x_M+49oI_h`?_h}L4>tG&w=;6gUKmy>nMxQs#< zaN%_8Lag)4n0P^dBD_orC1s^|?oq&)Y)uwnNcp_s;X>Eo0?*Q{zr;=JTn@011)7!j$QSgIH#k&H(uv> z1Fj7mj0hmk<=eksiWuRNig%XWzdf)+DyQXA*2y1G(GhlS_yXc_9*o#gazDfh=es46 zdw~K)6_ltF3aeyzrPwBsqG`ngn0Q@#==1}O=-alRJc%cD6nXo}BhvP;Ald_BBm99| z*>7=9V7rGA-7ox~khxfU$KfhrO*l|Nxh7_!w*$1oWJHH-qJO6vQ|o>!iV^@>cyRZ) z1SxCzNoo6X9B*d_Ru_kxHOI&bSM%mchh!wCcc+_{ zXdPSyyu(W=UrFog;$R1Q(Yhtt8kgv=FGA{4ZIGi~v5Wb#PxSEL;<0pmiZ>_pO0jki z#1jGYgD}px=d^|sDCQuu9FvMgq3O$cLNRSwf$a&Ei~WB?$5v=gha5aY->n1~f?ye| zu(=oKrCt@Ob{Wfo2d37tzVqIEi)*w$abo@k;h#>S_7z%hS(dtn z@Eo|V$ky=C-RrgMBV}yg9IOHs<4+p6ku8KTP(J%*L0&d$31H!Oq4k@zrHJ;jo|2zo z`!?lN^9*(?jEC%C9Ed?9K|4bKsGNk-P=_rVT+@@;msCi}&uVMB@egzUQ_j9q+{$;8 zp%6WMgF^t#quOURIJ@yNIyZFsS*^3fv5vK`E2TZJ-6ta9F~jm>I`}->w)?1Zt9H#e zgKK~}_R)Z;7(29QSj@u7-Il8EmK77$soNy(nP9HGrvKl+K{d zTQP4M2&?x3W69;Dz5o$7WnmNb1+6Ede)3)G>*&x+5E7GpV5di|(c+>K ztd;Os(lEQi_r<{RJ!_h|g2wNHR2WMu4`vNiJ$a1Gz?1f7%v1LF6ZZEe`+I}^jduZG zML)-KCSfXm6*Tb==^ip))e;iUeL)OkN%(t63mlIaGo;UH>#NYO;aD2KTN~0jnGdRm zFu^rW8!At`K*^m_J@npgZKy0Ar`XrDs}hVafT{7IQ*_qnRPY*BBST@jUh314UU^L$ zkPsMSPtlkf=fV4xWBiFC_h{E<1~q$%Zjxtw={1*0-d8rWUH-p3V?nmlSx1F?v`6&7 z75|1ej{@#&@s4HEiBjd42!z(hy_(1JV z$!{{*;v}7;+BWbx|IwMAO!MBvkQlilgqWsyM1liL33SN9F0jPkE5NyVRQei+>l{|( z&hS2}c?;76ym)fs($hLeZjAKs44k+i;wl6hUWBX;2~QJKT0G6$rxn^*zlDPkgjU%~ z`R?@ic995HiijtoI5wAZ_d{b~RbRRv6JKC688PYctvT-CCNv50xAtR8Gh9W-_iHI} zK{yjPt^R|4ClXVV=A(E6yJETU_-&}#=U z)CC-ZITf@^w^@J=cwpe5 zl<}a=d*A^V2DlcKy$2q^nF&1TY9rL?^m}M~pbuGKOlyuS*bAN?cq{l2YjY;$Gos-+ zfwp(*+{Gb_3d8BmE3}SM%^@&B)RimZE5!0H?-+`CUqkFpGlSNhOG^_VI9xVP<|N=X zE$D(vp{ftCjEfGp_rzme?NZ#d^+W7maAbIeyb%%+A8MghgXd}VN7_^y0BWZJ)uB-B zM+{Z)TN~AJI(E1L6&{LcfZP@`|D#<47jP~!hehmIPOODz?C!t?@v+v{$s`2@!myb5cZs6yiPEu;>g zVwzBHpo^bEr~{)BpHS-)7Z?S_z+~A;f|O3I9~0@VquQg62WjGGP>10GWPZl_q(804 zZ%V)q3L~&{4T~QU3hN{5a_WQG=u5<+{!B}VL+I~jxUGoF&$WJi0>0+S#wC~t*wrs% zR?s^*JB(xpmiExPuSpwN=&sMT%!FW);FQu0h@u4D)<0x@j+IJKrVd}QqbkN53n8Aq zK<6Zyqo$QIiSSD-^m!*VJblbVD3=hvNOvw@d3f5rHGo=U&g5;GB=iSwYotg*%0cOx45 zWUVKSFW1MiUnrZgq1vytbC^T92uF&GbiC_uzIy5#?Txs=yFi5@cP5f}I<91teut(C zsaZ{@zSU-DS~sI_oNjig8nqD~5eTX;`sLH+g{8YF_oUXN(^&U1Fa}Hk@9WS^EO7V? z=b}9)P^a>Ii()skI{V1VowVmWRA&zUzpD%2IHW19RvxP^J<;s{f7fUI7%Drdb+?;u z?GVkcb29B(NFRT%J>~d_7XARc3kUqMrNM4RfE_LmpHd&}-ZS$9h}6tzc=lk?&5eRG%6~X5sgH@X_PwAH z?kK!W$%N)*o>m&m7!R^CJ;!mt19{B>zh`bkHgdBBd#?^RsJ@js)?~%OY8pC=(wUv_ z-21P`45u-xYG^UrRO|)&8pox_*~l^G)9EwX`{F~ILDp~DJ+e7T_+as&HNKf?!V8(> zgbxv!}~CG zd;~k%{m*Ir;}8Jcsqz6L&LoWPwCtSrP+ahKA>i{|#L<~U#QfL)ytYyf=F`#gw9EuH zu!ECY0A>lmPQPmp$blPZ>)NzDQLnU#qAJo-cq!%T=B1?W)a!y45Y4ja|7_NAK3ei= z?FB78P8ov1tiUw0>BFRUydq6^a*_s8$4dKu==9vmw1jAu4!vGCF&yP zX@jWeUm9Y~l1598stP^zaJdDvR;uqSpE@OC?;rO}d0;NuGT$g?2( zA6?Qq#VLoI*C}o0jjd>}*R!x&#Xx<2Twrel_iDISxue3;cgxDFROrzA#3?&lpjjb! z_K`ye&z`4TS+D0Au5PlJR)S}H=%B0*hznLV6zA#YeCiOP+x#+qY*ND9Muic2W?Z1M zc?n}K?TXO*$bm=jKB?Zv8GyI&*Y$i^4Gs7+=aC$Kka8n+c%ZRoKKIEid~0ZHr2ezZ zwU1p`FTS3tV)S%5Jc7r)3jGkH7e&rCfA^ewpS@#pnDC2zlP5gq@!ju0J96@!jZJuu z#OWRQiqos^kMj2YILf17KO{R`PA55hu7Dr@CVh|Zod>Q1d^F&r0UrbS7!S5{$|Fal zQEht=XE6>NpU~O%`aQDo1I>xkyL(0AA+KxgWp3qcCfgQ*Us4WV<62B#v1My zS6&Omk`-%uo@q{))&Y(dvBpBS^zo!YVJm4{yfvF~P|4wOD9KNa>*2>yp<7QJ6!_As zK5xSqbDP6RHwv8AJU5=1DIORZQ`~=9j7NctDn~x^s#}TT^=|Z=TklXb;}fs?Y(1V? zE%01pGmgj{5S`Ta+JVm!FC9v2gri`JQ&OrA z04}N#P8#1F&KgJ=@p^hv_FG={g?h&0aJL!bb7&5OQQq*@)Wew9HHR_!;s_NmM{q;5 zfvM2oP4P%7osHM~B&F@}*3`q8!<)lk_tQwwQ?AP1=2f4w=`pd;YKq6`A$TJNynV;C z6ATT!$lAzuLcyyzo>l?}@nzxPLR%B`C*T~K+8l}5iY9i{6Xp0aTG&zFU1TIQ&zJtP zJD{Vx4J7IHn8e~&OA|d@lB$<9VOCu8a^~-%oDt7nF^hO5rgOxe($1c9Cn15^iyIqd zv};!G3R603SJ=M1H445K(tbB*~g zHRYOgn))UJCT)J>@R8sp(G&(pGz%HbxjP!`vi@lfgM-;U3?_UVhEshH{n;GG_`0&Q zo|G9s)2lX&=JU-#%r8#FC<_UEDGydp3ytio4}h1HNEu&9ZS}CrbMb z&B5P5{Hc+M;?0z2aIa8?%4!dkU_`%?e+Wtxo6~FHo1`ORBiFD?=m^)Cg9Xs=7w8kN zF$dAn6g|+6Q)KL8omAdB_)VynS8r8M=QbLcikV88^l0lJOvM+$B#jC(^lpxeG`c4PKTlhFGVrrh+f%E;Mgs4+i=|Z(pXzIb3zNZ~F0GdMEoMsj@fzKZk>+Rl$pt+*?mb42<-E z_gEUpCg6`W0T()Q-k#Be9`xy#%i*qc(5H95jC061 zGp%ha{?sT5raa5!yqrDj2u_N5PkM+tsQQ&jfomcTt-K`QjHldCZLBFa%nG_&)e-HM zvC&8l)eZD#%87iWFkd--4p|-vXkLqP6Xj!5c9N3Iz1Rc%M=ecS) zJ8!1k{`$@o6L)KxB9TCHQzX`D${3&za`74r#2X#JFnvWCmp5SQM^%^WJw2QoQpB{F zRo6N_ z+d#dy9Oy^u2I^O}E%|_7syqS#U4fhNbpv%oc;(W)o(>Jtzm+2p`+u;W?Rq+%9l7i@cKlr$NXbhPI>h3Hi$2*r@1V)V`SoCg~$ByE?~tz{UAE@n7?Na&KT?0 z6HezZ9u&d8wZe=xH(O7x#7wa68~l?5 zv^A5Ap}OC(42QJIRH|Jb?F3_12HvOjPxw1|Ib*C$xT2uRt)&yIl)8u=%-2bY@Sp)0 z77(B({Qd3L`~h7PWw*vb>M+(CnT#j>U0tGy4k{R?Ydv_=jC~P-Gi*ET1kir##@z1# zeei~RjYPFq(4HqjXT-0U%8MiBQ*xDmwP==Q;KfpOTRv+ew!)5A`B&P#dj%D2L|1c8 z7=38ZMt{%CcmNtfOB*QsEnj+=FFQrSrT$}3GXA~4TUJZh=~ zt^MxAQsp~#nD41ztqm-)TYIs5!MS!P)+*SEQW(D_N>Mp1IdKomSmnuME1bYxA}_ocd9r;+YlX-Q&a=zi z+n8sS@HrK&p(>^+5Vn@#Rsxg7wie#1<0hPx#q-^!G(-U4ZP0wC3(O&*u%=k(aQzGr}FU5BdXQO;VIOcA7k*I*H)?A^7F(L(T zvc*LrPONpLSs`|jNEB*Z8Hhq^!$qPjQLvV(VGupdtg-_gF<4JEyJ5Nmc?VdYv$%Li zI84S^7)eGl^P;>{Haal}N*qhWSQ?6xfMT{YHWYq9<8=7W$J*S%%dV_h=vVHD2xrMW z*@$9(lAC1dALb%?kJCKg%sX;`K(!A~(c-p>5JTx#fiD1uP|oc#<|ml~Q}zqyBDuyT zgyS&tlbkFMJw&4?GAiD+sd$`nITdqg;Y2+p$@*G!Cgv%@m;L-&3pyM#@EUQgrHs!P z(}hD~%p|>Ew6%vRrD-c7Q>bc`KZWj`q!-G@%XE4Yv-P&p$jNAvu_<(VvJTfX>0#!b zh~48-=9oBP@V*ky4lcCU2wIGcX^0tzxe|}>@U=k?;UUO6TUsVy1K7*vtxcoj`FcW< z^jHJkqJI~2x`7w_0i&DHZDJ2@8;&8zPt_lalO9AV88y{Q#ay~DRmVo}kCfaEx;xJa z!y||QVcq=kJ;Kb&$UZ}i){?-LFa&I)(;V$qx=X}?!{1QNEqdbcim-rFj7B(XB%{6D z6<}%XDpLeTIBZH-JQg2VsdgI>*ouEUDE3)6VTg~{+2#5P^w2atOQc|C&VN7cN{XId zpCaL;^L<=I{V<__YkKU1G#k*s_SJM9QxrpL;^qx|XPa}$=r7*c&gZPXhRu_F?IKvH zv3IsdP`8y(20B6csx-Ls4 zWX{qPQo`R0R)kN1(X!ptpCYz9owO6|C^_(7s++~M_-Xdr*};Dj|f_EBAfppTm0$=esQ~OD*>mDaDbIWrNa;ZYfJnD+x?2ba}u+$z;K;mo;_2u zp26ZMoO8orn{h$G3ssn+cms;NQS8foJ9&n( z^})UyJ==M!GQ{sbpUAv{XD+i7e-yt%{~$9t(8(pxOo1DmK4E~=oq4dru}sE{`4^L4 zOfK7OkB?#ETX{iru<|?%E|=(F121u&yCR2-xeyP=sBFyK3+L)Rdzg%3>)f*{^+^fc=|S!Q=qSMBv@y#!tM*(bT9@`UlJ?qHld^Q^x+B| zWkSjK>MLbeE*IvzsOCP%JpV9mr(TOd2mi2c4NYI9Cq>H2SF~)gzDSlfRu<_v6?>vM zdx={Zc#aO-z!Sp)PrnvHjTwYcntI{@vjT7(reRBm1FIuk!1PS!%zezn zF0NtX@n1bDDeyBxkOc&+aKr#*W%(+Gh#?3prraC+)pkqg(b*-iy#+(=B)t34^E&Zy zJKB(Bx3wE@D^E9X1O3S&eMxd-x-<*$oo)Cojp^o0+OkxCT|7T)T}g9_^`7>}6`}RT zI&;!KMP{*%H#nKLwt9#5EYtsRbUq2LMFvMQBg2jRwdGE%idAO8OPi^-M8C#0GhV{n zx|8NIF+g)(ITp#5Xg$j%D2rY)&wY>=G zE>{98*@g*U+!$QuZ^WSnF0qCG=4n;T%97f!ZEbikmNdYMp4dZ&9@MXj4!As=F*BW% zT&h=en*hH1S55S)SYr3xh7cutqi~}?ic6Og{EX(@?C z@xF;zDHwd%{)fzo{uGuN^N@Zm`D) z-60|yX>m#pXMbd{TX6u6N9f~ecUSu(vLPx3e3^JBrucsBoA+-zI>PCk%eH8|eLuQaW~LCNzpunaTTfrE&2sP`VnGc8oLB=bZ} z^@na{2^Lni_eRo;3An}iaRX_b!_NIwIK`jFy4~$Ou#aNb z=mTWuZW_Ht?|GT%-1ETvj*a_-O-S^Q#fXv7Rs~ z4RO((^@PDXO28?3hNpzFYxwPCtkrvW6RkYJV$_^4mFGm|%KM^nb10Rrg}z)hF_b&a zk7rntxfJ4Q=0$!y_c-0(*~N#6RZU%H_}{;dNpWPjx}KU7i>rGyQe)J?)w{6=ITa#-5odBU%wvv=U$M4Q6fsEYJ#L7`N}L}c1B<&;ffg`iMs1G~xJRd%UtxSDf9 zHM9I1;furv@AYIo4jHr#Q{im?9X7~FxZC@?cIFVqaEuX{j4T)%m{!IYQJ1J}J!~g~ zJq-=R6$~%C-Om|cb34R**Dve=@iSy?(FY7bFC-`>FD zRJIA*D=Ob!xg&IJlO7#`D19OGZvUh8HCMpH9W56uOQ5aKu&J|*jyO-b9D)g)ZP9!|{&QvtVmU9^o5PMRzKF7SpyUJuj5M&_4#k z%!OnkB|ontoFCtB@i2BFfFsK>;KcAe*4TKt_2MG`2A9Mkbc%Wbb`Srs`h<)Z^i7UL zt6SDGIDzJ@#BSn}c2I07!~rBXU3`(P*WkVJ0J@bY;*hG>V*e1kl2|(SlK!lV^UZvd zN^2l`*ts-{{KJ{()zt_d#cl(SmT#j&MSd=IiFm6cn@OE=zJW)Jt6Os(WcfdLRg&xOR3jV|4oAP<_A=|)Q^~rjFY%1wsmPeug!O3)fW3lxz@3fHWC+3m-*8f6*W8bP9r!K;cx>Li*1F+8*N2l{)%d#0^5C1bgjyr z4xH+Kl)+St=N>kH9T-osJHhCZ(bQ|Fo_)2Di)Z*G39ZW3$kWy;3k8P*dm1V$Xja+Z zcp9uhyLvbu?^!`x8R7$Tx$d%?y@A#T{qsD$7O4()UknWH)?&CKctB}LPwU3%HF}j7r4eMludFk6vsno06%UwySUtD) zx?>)muhi%7qJgjLd)tXZSK5W1rTUiDgK^W3_2h$_x?83H;nvaHHRvbvp^d%WFqyo(Z)E*vg0kU_Bz`QtA$ zxWwN%O;!>cI)5gg<^C*pmbsvzV(kL)l#2r0M1k4-aMpUVwt1nFLv;F0DCf6dpqhsu zuD}G%{0=TL_t znx*$2$`ML<$JC01%t>>tuivnlP+$0d&e127pXOTKUZ1v9k?s68HuC$(df1=l5iGvG zLA=EGIJ)>SMj0o=oJGlH{y`ow{_0?jW2Ck-Kd-cSkipyyRSXaU>5-e#) z`Fu4z*2B`2;I|@A`5vxoTOLy4_ccV49n$Gum{t<=3OWeUW^#%HfG-YXH8g_LB2Olg~ zTsE9_nMd^c!=fT9Q+$`yfA{p{F@X&h-Bo`cX;YLzETbfN7mJ!?v#W=wG_b5WteIw~ zFBh$?-<@Wpu*$+q8Y?rBZAv%W1a+h2ZE4AL=n;sO=-ES5 z_Xu=6=)_9te#$NP=XK_q$J(=f*<+X&*W$f*oX>NByai;H`$u)gLK_?2l{TxYFlpAe zE{RIR`v2qW%j27>n!j(-rfEwlrJ)TJgtC-PmfD-7P+6{EiVH$P@IgTZ5kwK?aYY|B zx0V#d4W9^uii!%jp;iHd`&A5}BGyM#RMZMCsOVD_5Eb?P&YYX%wmiT0kABjbGiT1s zoH=vWd(Iu+FlOSf;Ksxk@2ni&j)6_sB4ZYd!&NkYOT|}ei`mMEPup7YG~TA>SZ7^F z>!|W9jOGwEBb2uSvlPw~4G*N66_sDmU2j&Ds4&WtUHFIKjTdR@-jKbyZ9Gp6dqV-TdLNrdf$bINjId6OEnL_pwq!}0 znYW$jjYSt8NKFw{_9yv^-M!~{up3wl_GTO2tRazHJAoRvSCo_(BlqSW{~Oi}zg0Av z?S00hl=*hWWBoOq^QG1mHJ->Djch)_^NzFdGs|%d0mD2g81wSJJ1TGqk7yi=Puo$k z)}5b)J@BL%%q3LtZbk8+qQCg#V_wx$3t;^2;OIXc|DWdg|3)%4pYvI=L@Ix;;s&?%9yPp& z{ir6+j8B&u-$RG0HPZg~D!P_vJN9O^IgHZ@unu3(2kQu(HiUZZtazfE0M-CLZKG-r z0}{S(MKL=T-y>j6LFMR29p0}P<<_Rsl=tyrzoO_t=KB>T{k4tCn09V4n=uhaMv-iM za8yQqhF(u)HapY)_c8KTGIXSlA5;w2C963GLkfK8!&$KmpU(bpl3fgo{fecrmKJ}2 z0WvN>+WA4np#J84DN&e4_*uuNL`mh-R?>hEE5?n}aEcb?z-6TzC3+x5pDz2(^||M} ze0exTu>>0p2c}}Q#shU8!6gl5{Yl$COlqY4K?goeYGmQGr>zkrkQ}Q0VF86p=lgO~ zMp{hg@8T_hI%?PjjVv=IA(tc)@+DrjaRv7a55RAr?2mAgW%G#33vlVItjDrDW;{;w zKSIrU{-zBdVZ$HCk`H`T(Z6`h@0dKg`69Uah=_F6%$J=oWec#IV_^!*&ut9 zS2^2XwEH^@)xBTy7r!&~J}5Qrjp_gEvtLMr&wlTqBG7CKe@ZOjvxz_BP2bBBJKjzC zf!EkCrF}o}8v7T1KQdH~=}rYdR^XH0c&kr-FZw?|`Hka~-;0h~V-Fz|*H@S0W-zpE z?Khgg1drIR`w?@S#K3stj}^tP{w6G0n+0!Z3opT=OyUXoKE$_{IIS%eG~;lFv5>Ym zSM)CCBW+k9ZjsOYld^xRn5S%PTob?Ur;1x$r#3Q6a{;zEu}>w(84yIILeItsauhEQ z`h(n;d49sm1Riv>I{G~@LNHn^R@>;g&0h>SRNspx{Zdh#8_oA`MA&QN=|Zc2sko{u z92{SX@NN`VWAOz;8=O-@(^X|eXvl$z^Fr3SKF=zs#O1HD(~J|bQqVVDet2iR^amwQ3w~Z9>l7!0M;zpez0PRTRYoyoQI=VWZ3_%k+pN#T zX^5PLr#W$_OPHCp#9w!Aw0hE=hpGAX(W-o#PS z70c1ET8f@pTt{0#(|<#cq5SAdTKpS2Q+&Kw{yUH==Pa7?J1Ry2=hCL%E543|yDKkB z+<@?uZ_DunPGsdXzOFKSx};ZypW?JSJ^Y2xRED1wydHj1=thK3l;4pF;Zawf*dXwb z@UQY)5$?~w8G*z&`5l>X3BSnj@CsFEcsEvr^8`86vsQ4!JvR&S(C8WRJ0jX!evkK@ zD(SzJ9HCJRFc0iEvMawDkdii+~@N#%agmbC`X zjcYV%?5xH+QgYA}AXTLo*p2gVLe=7g)Ctgb91geDVE$jzbI7|j{)5}$0-hN*{ZiWn z@)UhmE$C}NKN0j3K|fI}5R86DqVmS*4pl(b)5>S+zoq?up{<$4wBYZGGu+0`c;nwV zoy@n3%y;Qa@;zu?I7v||G0&jV6$6inm$~&bae8A0nVEWV4=ap?+H7g~WgK`CpW-VB zwGE-1>^0hysaLp-S7?8x-aj||mY?ao;kT&NqaWjyR)zrpZp9o**L(Dj3bhl_q$Rv5 zt6F{IbF%as@BtQ1nR@j%tBkI`Oca3&Kw~Nf+Rkmd5d-tnqD1dbiDF6h@P(TC^4#b` zB|>x|F4WYI@i%cpHzuowUygt(@FcQw^od=K?8+ido7r{s0&bq%lUCw0e7nB)Q+cjF zqS$mFou++53v>1A63;_8T$rWmEBpjb+-DN%kdJ%Czs%JWE`1p$6K%rR^M0{P@eJT^ z1XYei9df(v9N%Hq>yEWaETP?bI)3|XRxor1HjqSfv7?tKI>FT(;>N9_3F(rEU&XnU+&z$KEz#(!yldwrl+al4dC z3-#wKaA8V{EBZ8*c3$1aw%Xp69vrT`|7T`~iR^x1>W%KFJfB{2Ug9^z|4j6$SPqbe zFi_DY4z)UzspnL_@S!+diqFW{{IC?nCp*ON%#D1q<5mS2>&WP! zU*gtIriKnWF3X>mnmj2poWPgmPop74ddVr)CSQ(R@`TUt#obSjL^sTCqOLjW5@miu8(8taYvUj`=_M9@~mNdt?UjbJa8Ig!F9Wft=LlWw*MD@Ir{Y@({kXx05$s-AylVYPlU?f%XS?*oBij0H zv*dr;14nz|wYlpPn=}Gl-HX{z;_g$uB!AR5>$mLEXdiGdEj}&&Wk)@TUzAg*YDk-*%BkfCFMBDRbuN8bqKEiJ%r2dEd^GzhE=bkKxkF}SvMSm9w)bvK zMLdr*gELbm7e%b&==EdtDtBVS@~+@zJxRT~>hrvfGO|IZ)lDz*a>l4BV3n&#p^d@lC4ALQ7u2^0U;hpS_rM%#C}PU>DE&HghF#AI+$z@<+j7u#+yp@{ooR3ny-x`)?NDM* z@*xKzW;TiaaHrq=9y;!>`hpsJ=wG|7WwfcMzLpO>P49&Y({NWsFNklvO55>!k@<@4 z1O>LET!%`}vMc>1I}MZFpCWk8v_Rp_>);^0Y+S%WkEK1KJ13bhou)lUHD!8n$c)Ew zv7D|PuN7Yn!$Zk0Jb8?&%0ts%S*Dkin9tbx3Yf2aP@!7T)6`g|7mZh~1a<0Q!gF8c zbWhlsML`*Y3*J~~x^%(Tg*FbxL5x@B&!MLN za9{8sp3j=-i;#!ZPSgDTHh zB{2(E_w<8aRwb?I$KHkS(faErbdyAmJ7OtiQLaXn32_HP_P4s*=?+VpJ#Cyr0HX(6 z60Uj<9qA9HjA>-{)BQP}dFX=~3GOc)p!+9J`QN4S)xk;%M_pqSoWv#TOY_?}hl#Bs zn7E|Envfz#Er~CSB1Vmk7e5ut3f>w=)&RY@+Qe>D>tYN{xCQ4ZMr&*1l5I~6W*h5d zssS&z<)t|T^sXglILTA_e#)pP(ki68wNX-be+zN2b=jut=&}usRje|GCCO9XuT-hB z@c|wb;C$&7>pf5N0$`RB&%)-isCp=wKkcB#;iHSwezkG`OI2M|?P~ou#S1DR+&CQ0 z8mt`7{GO%_g2UlugUrEtHJ@T0JD7dL&%WjF_rA@-;ab)QHqPN%=KJhgon7tm(GhZ+ z?bx%>e6}wyXIth`X}R9dyGo|$%~Vs4lJK$Eu;cV@E<6_l#UqAwbV=H4N0($J>HbG6 zvX0pF1^MHEX~*ep`PM=R<3IV?qh+z;N6TV98*>;|;;X9c zpObQsH3SW;*)H~c))=<^QA#;G87Q5$O$Jq`ZP)!DrR=jyK`fH$Wp6LEz5N@SUxA<| z7RT+Lw^Zo$CDv{`158(om*|tk#wRpD*Q>gkAKHQ7THW&ixRWd|>e@eo(lLxYXC`?nv1tn8^Ze4)6$__Ef>?eq1nN|9Po&p$iY{Dzp4V5>c<|GYgPnCpY?ZSK75>~NBR*>_Ry+{|?8 zycWU?RsooIL=pTHTatsm5~nw0Jcm9_m}!H2xeA}|Teba6mu9B@2)LaC{sAyv?c#A^ zQYf<@?61D<8Y@8j9 zjL%#0G+a&8Gy*edV>i`|)bDfSZm#B$`lyJNYZE4`WgFnGN-I>A@~LdbiIz&M1Yprh zs#7V&RRpDA3867JOP;h+3QjAN3l-4?dl-ox1nu$dHkt#`i60inpzE5MqCb^*wDQk74@Kklf|0~ zPOHE?`otn>#6v)^{7#*kY+RnL)4hOENRp{>pA9EHFH zq4-)md^btsD;H1UMyc9TSoR(bi`FIy1h%8_e<;CgmwWj=2csiD3yA#PZejJ<3vuNIiCCF$lhfR(ir zyZ~_jSPQ<``nKV;f)R@YZ7V5xe(RLdnlEswFzYhFj>2$#3&*z>g&9u*$5kUvs)W=q zN)x_mT*R~9OrnM{`lu@FHsOVuNmr?PtBteev`$I#O1D5wb@GPFKw$?p7n zaGoz^18oiHPX_O@w7xvzaZLrzCpfPv@Jm`b5sFz~Ad!W^_M|kq2V%JAMR`C{G3$P$ zw@nvND)WE5*Efj0s-nd#Db z%?-dIF0|mc9{ff#9nzBg=Hve)zhja<(*P5}hh3FmX#2eR6z!X=pI2-=ikNZ|ZWp`8-HqQiH4!ElgPXWv^kE4CEz1~GN|Io4by&QOK<)zxjpLqO4_|+U5FhxHjqJy^ z3`cB&!9b{~Wr~T#ovNBf3KOlLz`)t2vEd|B?O4=fJE_}LK~^$P(saFT9?7bTl(j-hP6x<8xJdRU6y=ZI95M0V9%x;P%naAu7xG2rTELHTJ9+ApB1_++*s6n4H zA-5>T*{#JWQE-x}(FJhlG*hE9;I2$Bjv_p)f7m#?g=s~t;0``aF3?2n@rPtWGg3Ia z30m+nrb!lTb%?d8?W3AY5@-5+YN-JehGZ)+3XsnUqiSSqr3Ph6z|#;oIVPmqB9D78 z0828~@&ONYz-<9zLY+#_5jaiX2JO4M5B$=3EI69-Eg$ETf{kkaAABOVBbb?jNHH?A z06RS0^ngh(rcutvw>)srNWrdFFa+ShlN^$of2#J_3id=&4E_eQc4?{2zraAN!d+aLFPPEd7GA@=X)Hnp#VJ+iVfm1CA&jq6X;WSAhK+wW;!T@!js?(pr zz~KwVftG$?{G!saPo~=ak1@8A3~j(e)%hUc(25k#2sYJ!M5b~e%k6fJF%rW`p(I^* zz(3gZcAM6|11w`>(Oe2K`!X(uKgHAfTER)4);_>P!82L^);B<~5XlT*0)``Ex*(eH zSV>@8NNW$^VXRrYP=nh!$Le7!kNFv3?nE3OuW@V`C;4~{c7BBSEqH`kI}U^=*%tT| z@F>7SXa{(1-;5h&3$zRWiva0P0M9|G)eY&S>`;u}PF6Q$+HO}tG46Jrk`ZuCsiVnf z_U=q8&ef|T78L`;5b+SQgbFe6)SuZ?SKtDO)y#l+eQxFE&Ew6*~D#ai&- zk6am-tbEh5X?%*Og0U@@ zk~meUv8fdti38D1c}B{FzcMZcX0{180xo0NVWERIuFSR&Rx3c0QpVyueI4)ywPLHL z9O>W@(S8Equ`&GF5j0awO=OZ$TMKIYrp6!BmkuhDUYkrOyCFb=epwvYT9{|k*& zl{D9g@h*ti*}B;U+%9lhpgREfa0s;2rcbttTW#2OM3du&qy3vVwSpJh^eR3?Od+r( zPmLtEfruqfI%U1UDWMEzVx)yK7TNT}Z704Fd2LOTV`U4?n?s^%ZFZb_mA0L)Ut1A< z-@g`T#zI*S5`J-j_Dh^s9)Tm2Bk*~}2z*Fu_}9n*+OC9O9Ku{kSIp8UMocu0+5rg3 zL(;WjGyqr85+?^3N3_IQPk`>kmN;`AaHq7y8E8DUZs2;Oj6yrCJcd2W4lxSP*4w+y zM`+4yz22>@qNdsUpon%aGBB~j6^uH@fyoe?!BoI3kkHx2xC?Lz@J?k`_;PAb1TM{Q zy7XN)Fb?!derMo+p~2W9)dKGXvJ`|)hA}Wa1-RA>uVEbMlME-|f5kA(?{?ruuoZml z3F5!}kX0>z6os*c!ewG?aVr(f(JzV^^=SUwFdSWr7R8*Gy9V@mDR-;(Ux{@i+;c4W zXcBLp=xgK3R8xT@&KNClipChl{A1kel|Uyb81%;~gyG9|vsK4Nu(^EF}xhx*RxJh>?aNIP)^5L*A1WFKaMh z4j&F)#(dCYyx^Lu*8EigmjcPAQ!6{FfO%Ni8P0@YkYtF_l42%-Pw0%f$lI0a90Fei zTpn;vesk>gjU>NLymQMPon-WJB`b!rahrwSdp0UL*EJrQ(AU@tkIF(lV!2pQ$>H#B z&jAFlb>{-Xuba|dD}@4OEvv%niu7YSpKYOID0?n1b#$d$Z=uT<gg3drUl5KQp){dNChFfOfLQ+2%73b6z$Ba z0T+N6m+8GnnBO4noK^~do#GM2G*;1nmEwV&3Wc-w(rWOC7+<95Q%2L8QuHYv)@Q)A zGMbiPTr6cYYbE{{8lHNqa`=6}+9?8y4a^lXE$4KGN1GtfE19?ZV7wS#03Zcv7!uabbHGcH?;>#}m434{u~c}|mb6O8kg&Dk%{PE+ zWd!kps@V9H70g9oWLqIsV_SebKOMg@(&0WJ70-t048 zLz3Z@_+OZ%J3(y&aMhr5GUT&r7#T4nlB!9bUrEpJ2p%^wE(ThaPdf{+3$SBo0l!zcGTX|NZ5R)rp&k6gv?jG8 zI2~}O7|$-0QWI?$S13vJnb0b|25_r^m2n5|UebH_w{8O;R*tt`?73sm79E0ykRSFOD0^r62r)C^V zpxF^1Cj*JkyWt~()Mf$40{PN7YbJ0rfKv+wis5;{T>zXkI9o%ekzt_>Q53)Fsxgb^ zg^JEP2Md1lvEWBNpF6&Lyvx7zOI-bpFj_pD2a_lSewFz|;CM}^7YA-T^C)V#K|dqk z^O6+Oz@Pr$%4IOQo1VE|-`U?RJDQQv>u5$=PsJ#4pD?TX;}!ju1BxFmoNK7nOCr(XDjnYeOL_I36~Fq^z^@SeI)GmX@av#FJ=(0~ z^K4c0S*I(0^#eiQ0rbV7F9vcllW){7bX$99!;LtS5M4yO zZ`5z>q3t4ry;r-uabH8VF0TV7_;X;)I|A`A%3<-$BOTmt9B+&9(q{()IS zE(@K;X=gBv?YK26pS&jO$Y&uSJM&l*;ox3eVb#VbTW)4nEbW)K`6JNGmlG}I#B_o= z9-G4%G7L-+8{@ceRv;~qwM2wY(ePJ2SddP`rz*Zlp|um0&`~shlm}%8C~eG>)R;4= zy*VakOY3Ns3u)D2d~=Hleuta%XdiLp#O;1KFdTiFa*Qqa`4{n&Wz0u(H5@y>btEo@ z)h8B5bBHyq_vFPqO>R|p#(!w~4}Hqwr!CP>aJgT@gVs0eU30e`PnRL*Gox;xO*iZP z^Xr~nKk9VNe>u47o4Zi+&H96G>qNTq79EdCPbTA5obe8Krz^QxC1xtOuD(w-gDn_y z--?eZjqhptZTe+ZR;eF!HtoOg5&0n1L>}nip9TIwPmS&F53p8Bqv{WEQ^d`bce_5W z*!)=R=kaj&-r079kK*%h*L%BqC(zy=$mRmT=ze~xMYW;C+rVcje6*2XTng6@Um4%M zR3G8#5k;J=?WEd^HP0XBBR^pT?X?GZ({ zlq}pDY711E#+gIty1Q^}-U`vCyYxZ1=nj?8hpG84e6wl(NPX|dN%!c%_}IH~tlq6{ zi!WWN|LpGJc{|O;_)z6a>`ddd4`}uM`ent|4x8iBbej1#4OoQ=h^`=%=Btn19pjHP zP5Fp(E-hW9_vqnyK22}DZu5UNjl;)?J6GwKl~^zMgW!=HzMj)!9*o(PC7;KO^ZN2a ztDz;{dWy@|>G%irxLbQLe&9jGmy)`D>o3oAt^e8WTEDH(wf?n>H2)>A=ZO3bG+;Hp zbsBdtW2DQgkKXIjFVAr4qc^+saUZ+%g^vy_d`sC58PK$U_Ikw^x}HZ;pv=d8}z%prEFF+!kKCn zpk2*5ZNR*QvtMYFT|n18tJfE57(&^GlkD2L5V4d3as7ru4dcfaX_M&nI6fNECQ#<4 zmNlgEh9&RLO`P}mR(Y%Jyg^$19OoU-D*af=d&Tpdw|lF!Qaf*FI`IYl%@U)Xzl=R9 z(FnR@#iOKrtXlSc5q2>$seylSckYmv82*Kwiw<*OD#U`_{#EEp@;D-WN>6NHc|udZsRekd5xp(>XtGZ z4^iW5oW6p~2AeymNq%pkn%DI+3aw~MdTSx4m(s4+b=;@Q6>LT5@auZiFMzfnMXunh znY<^(6MD5xF~1eXrPN^yTtdjrS+sJCeo^o0=k)5?F8>(BoXSPf^;&dnkJBNeI2s zUeO!41AjLnm*s9HlZ*E4W`%f(R#{I;bcj}b$_oFYB>Ur2{a=N0D5gBd4xos>p~atZ z=1-B?iQi2_KIhCI(t^)9eMhVGx2bOv<2Sd$zh>uqi9b5(5)XW#k8qV}kNOYp=TSV? z4P72_RVm$km~Ppl|GSVs>v7_Zd#QXcMz0zBY4={eBs4m%j~?yv4}u$wxb3&~o3GK< z|FT(Izgc(bJKn|+VTVRYt9yAzg+A_OmwzzmMz*^vKHy6|?CRG1GY5|aB0(;9>ezu` zUl+V_H7)&0zt=B-Hm_x(b}{YR7$~Llzvke~b8|;dZ3Z3q8Wzz0(F%V?eDyc_Yo3V7 z?a(D_lS+hxEJ7?Z{ISAgJfKAQ74s;xYkN+lBst`3+Xj8IT3LvBuo&CKY8VxRz)2qD`H$)FzY{n z<*pkjUXFv@aGbif+{b5*L1b*1r7z@?W!r7H2QO{7I#nrvE@)=`&y z=u&XwZ4Dj=%=K+IEk29lw2bjYORMlzEn?ZxcK$~MwuMLgH*op1GYIk52~vQqEsqh! z4}3NQ1*fz(*0zj_*r!l++s&qbK;Sg}Lx8JoYfa#A`JkO4snNYL+jO#MqpAQspKSN4 zHGO4Lv~4*(q}J^P$JZSEqF*atin3MEgDQ`|!|qvFdsr{&yhaRgl>`1aV0L;(Iozv? z1syHZeA~v^MoO+=VTFpz!Q}DGoF_PE3kYaE#G|g-&xi(j5Qr6M9+8lYb3tQ38QRxT+stRTT zE{oY!P^ysTLl|UmCnViFH*=f#L9!0%#f9c7e-TDu!9*5$crp;4NBa)xRpX*@e=+c( ztc8SMOb)hS8So@rWq1(NnhprJSa=VtuXVEvQp+VPvjOWJ&n@Tasi$Z zYr#y8(MfDgOD}tut*mB^w0YsxX{nn(0Z(no%N!0I^Pg&$7x_aWlG<6E>3oMtj{ugc zkP(Wq&`{t;#}E9S;w~d|uw6(}qaPHUQs}>coeCxUafcAbv1$G(&+ZSLC~o`UH-I@lJLIzZ$iShc zU?z{*m9VLLHp&=>%(jp+ZU>wcQoc%c2+8+&w6?m|J;j$JnzC@Wr2p70Mf(&)oluZN zO7j@t*biLk>f(>3T346W*~ZyI8oL0us(Pzqt9;VK_>+XTQ|$zd=y*vX1p0U`LCSaX-gc@QGm9temnPh}gt3Q&Bh>x3dNgN40qV z=BQWgO~4$RofgXlt`#rC4g*eJS~l0egPE}v8INnpjE|okrEw^5)k7~D~q5eMujj8{g*)Q-aVt{uVIj;KAO zc&Juo`wY+HA!Nj!WhjZbt#iFOEyC@caY?V{aX8?l_I&4rGd}RRT{LyX2l?=v`&4yI zN6Iqyfo^IH_3tzZ2MIRaa8f=I6_LgrS;ysVe!*#w9JVQo%`~WIf3deE2ivqb%?daBKmGUzr>q zBCM^$EXIdGIxVnF!O6l*0_?QFa==nO4hy`8N#$f4pR~ZzSjqz6rK+GY<7E0cBk+P( z-M;!bt;`JckC?Awl}$bzm7$;V42yAKfhR+`Z!~X^aFpYLc#Kbt$V|XR0xR1^AO^-g zil3eL1@J{hIB_z4<&dYz@ij$=b8eY97u%v>?P>+5x|wSLI}2P8vl;tRQQq9Zdu!C7 z;hc&2APzuiJ+%i4{TM3Z>iSMMe`mO>U!;9Gf!^*dUMk4N@0fM*A-RDpxBE4n zjJ!a1Zw7eln{T2yc}U&-V|-~|poiPND37++AobU`uoJN8JldU))J0nQWHspPLxX zrpL>yP$wtajxO#H81A*it**wU(t#oc z;BvO@9RgtmX#aGi7?;KaMS(52e*L`ok>Wt%kX&nze;H356Wik*#|M_U+>3so)irFr z(QH!uKEl@QL~SPoI^`xt`X_VQ;UF&4U{m51QNS?e;0bKXbu?!};5>KqSlT`zfcF$u z+sT#G403EbQ})EbAU7UR8Zt3Z=G`dvUP#Y_{Roe(YGm#Me;c z*=)lvV?F4cdMH4hxBN6c?_59h|`Vl*5sgZS-uqG1$aa%x|7C$C?yWs(!R5>>n^y7fmL}T9ztuCSS>Sop@ru9){Lpsu6@fvy zR;_>5e)jeo;(f1#aBj0CKIiJdK(}`V*bZ5IBdxp!*|QCLU4E-*KYnwvv)A8vP}A2x zLvLLJk+MI>^EQF19tj@b=FoJR^Ym4mqh)EF)tgpa8(31Tb+ywvJJPz)kbj}p!X0S- zzXCTFYwc~Cdnz+Zz5wE?7LXp<~JI4BY=9Y zS1bZ7<&=Mm4@L2ICV&`H^t!ru)3QJ~(_6>T=yl5%!FZc5q`v&SV@(`Hy>tRxvz&ZG79Ufl*#}{l~1?K+c{ql*Cr~ZE@w41*RWD(71`g5juzI()X88^F?Z73)H(4KhduH0z2GWKBGtOM>m;;*Yfyx%;VII->%*#^i7jp`eM%s>!XuT zSik6?wtiz=qXj5r)3(Q{d{y8!x8^2mRiL7`JZn@C^I+CfD!~`88HnF+?m473!ylGb z^?tnL1A#r6?rqP|ku`x4{i8GZy$q<|gG5bpu0P0xo(u8%g#)i$6hD7$;1o}xQN+Y` zLEKg%8H^5OJs$Y(JpRD1wg>Fi#b)FZMwuSW3W4VVi_mKsfYle*3U&jA)U`cikXOnQ znOA1@Tbgu&=)nhb3>dfHIl6M?G2@MQlPz=yVUC;VdYaz0IYB5)4hL(7*`QR5SV z{u85aDcl=%3*%&;q{%3$3#a+A!g#t#nkp(Dg}0zFN)(OfFGb_|i^e{Q=A1Y{oVPx4 z2**ru%1Is*y)}N_lYxs|#o_N_7~|p5I=tbOg)^e^FwiV&db;H{(Y#o(YtV5oX3+GnZtF@V?COtFfF;coMNYulqnqo}z%S9e}Q=PMeN-& zo>f*KPu8TtV`$8WeLCSdP@wBLV+%N|ugs*b%!Oi>9M3(1=aI3h!+OAKq^#g5V2q4i z>aiZh9p4OZ2;l6H6n#B!7MIeLje%=y42}S74B&e~o`R_&g;LgK+ogpxE>0Dt(&r|N z@$s}xaeo+#VOh+_;Zkd3IkL9z;BB5SWw9EP&z$Y6OzNQ!vr^2XNh0k*;8bkjc%ceh zMa`vsI@11U1E)mfQ*@jjNF`43m%(Rp!k417t`1Gk0^HpJp9z?&SzT|Z7%%g+kzH!R z$!@3MjXQ-`G^sJao@(?4EaY=@< zp(HfsKYd8&IuvUPP8Rmng{n%?fuIpSQrD`yOMsI}UPMf$3S`Go%-B&>0dpA_1F>C? zeF5hI7CJ>^TnL;9Z#zjJ1t<8Fk9of5Qo^0tzmSQ5GEwIVNaTHEITW}Pv^;C?V zg_|>gV;cFg(iUjCFIN_=9o93tfkvuUT7gpdY#&xYZ1X`{rSUXjn0C$*RX|c3*}LzY zc1o)=(p#C=n4H@zf1-jH1LF$Inh>I4Iy5PXsyHS)|HZ&iZ?;dvv){MktX`mN zey9a0?f(Bu~)?+^b-afwK^+1u!JDmm7=Fx^k;Ibl5J>EFW zq;e_y-I%vP>sfw)Mm|4mctPwYl(8}DrZuc};#6w56^feO24~W$ErHYUEEtAU(WP`? zOQ0%0(NDj9o#tnSay_*)Y->^>>u@}8Ti_+w!>MP#~+~79y;$0d8yR|o{W@q54Eb~>oCIx?L(`QC};QN7qr%m%uJoLB# zj}9s{z5Q|E3Acr#6`uw=yFQ}w#(sFGR^00yYUtRz6W!X_uWvUG%oU9q{w!3gH*171 zs~KYeu$a!25WL~EKF36aC}9&-gQ(m=WUj;qM;e^e#m#|)_8>OX8nq-|jTGuOV{6Y& zkB+bl#H~h49lR_`=3!nLp{Rxz_gs|sbiei)7`Zbkyx#}sFKxQbcPm^GK2=WQ>h2=r^FVP`Vt_JUb$?&hbY;96ai@7sx#g8=z&{Xc(m)jrCQxD$CPD$yJZF zH<1f(a)=k5m&_*)qP%HxsqG<-!babu7|mh^tqQAKWEX<8rdC33j@tQ3xHgl8*$OPA z1S=Q5HmSh*Y3)Yes1l>Il8NcGIy2_2N7T-8r8K-TTH?!axnmjSN%!gO?+xZz^%2oL zyS|uzW7)W7tKr#xMP6w{I5_>{%21hCoNV)cDtIQ)$^RaE+~x`X(enGO`W?N6n*Mui zaWUgE#w%RL2K8Hq2co{f;*}?ldhNj!%lwv3+7qZMHflLy#d7gx8xIU53Rtsf#h$Na=BJMKl_p_fbOS}vn#jGla1sqEYEy4~loTzruRye#P# zNMm}GN>3RyyfZs%R?!z+56NfM{WDqS(I?Q-fxSxOUw#=F=<-S)+!@>P>%c|D#tF%1 z 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

    vp1|ZHASVx5gSBuu3CW|P-{Da> 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�iHZPy#$|fCD)L-2^@gdh&Ac4#RH) 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%0D=!FN@Uz#<9d0j8M=b)+Jav7BbGr(yNm-};T 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

    ;Sug3lob<>-VxyJQNw_P95{XS@s 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

    dO~v=g1ZyDi>S$atjn;YjMwU({Am;!k2jc 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 Wc&WqSk98QlNY=~-D*4QBAqCfY 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 WEs}3j+Slbz%Pkk2D)}cxmr2+xyGlhpO>V!R=-) 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

    0mX2s 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�fMenSSl)o%#F5i2KT3h-f`SQ)%>dA$WNeQ<;$ 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 delta 1977121 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

  • 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 delta 1303965 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�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 z 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%0D5_BjZIS?SgP(+c!+ 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

    o7wC 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 ahB;hwDyA{7ATt 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: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 Vec { /// bytes. pub fn to_encoded_path(mut nibs: &[u8], is_leaf: bool) -> Vec { let mut prefix = (is_leaf as u8) * 0x20; - if nibs.len() % 2 != 0 { + if !nibs.len().is_multiple_of(2) { prefix += 0x10 + nibs[0]; nibs = &nibs[1..]; } @@ -986,7 +986,7 @@ pub fn mpt_from_proof(proof_nodes: &[MptNode]) -> Result Date: Tue, 18 Aug 2026 06:27:03 +0800 Subject: [PATCH 36/38] feat: support pending batches during submitter cutover --- bindings/bin/rollup_deployed.hex | 2 +- .../bindings/centralization_cleanup_test.go | 12 +- bindings/bindings/rollup.go | 94 ++-- bindings/bindings/rollup_more.go | 4 +- common/batch/batch_cache.go | 371 ++++++++++++++- common/batch/batch_transition_test.go | 434 ++++++++++++++++++ common/batch/interfaces.go | 1 + contracts/contracts/l1/rollup/IRollup.sol | 10 +- contracts/contracts/l1/rollup/Rollup.sol | 26 +- contracts/contracts/test/Rollup.t.sol | 45 +- .../upgrade_rollup_proxy.spec.ts | 161 +++++++ contracts/tasks/README.md | 13 +- contracts/tasks/proxy_upgrade.ts | 103 ++++- tx-submitter/iface/rollup.go | 1 + tx-submitter/mock/rollup.go | 12 + tx-submitter/services/rollup.go | 81 ++-- tx-submitter/services/rollup_handle_test.go | 21 + 17 files changed, 1279 insertions(+), 112 deletions(-) create mode 100644 common/batch/batch_transition_test.go create mode 100644 contracts/integration-test/upgrade_rollup_proxy.spec.ts diff --git a/bindings/bin/rollup_deployed.hex b/bindings/bin/rollup_deployed.hex index 4f4b9da32..493a04775 100644 --- a/bindings/bin/rollup_deployed.hex +++ b/bindings/bin/rollup_deployed.hex @@ -1 +1 @@ -0x60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610af6578063f2fde38b14610b15578063f8fa010f14610b34578063fb1e8b0414610b53575f80fd5b8063d8dc99d214610aad578063de8b303514610ac2578063dff7827e14610ae1575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a47578063ce5db8d614610a5a578063cf9a674514610a6f578063d279c19114610a8e575f80fd5b8063b8d0a1b0146109ea578063bedb86fb14610a09578063c555389214610a28575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d314610978578063b34844251461098d578063b35dac4e146109ac578063b3e0a509146109cb575f80fd5b8063a479265d14610919578063a4f209b01461092e578063abc8d68d1461094d575f80fd5b8063910129d411610198578063910129d41461087c57806397fc007c146108ad578063a3c9e94c146108cc578063a415d8dc146108eb575f80fd5b806388b1ea09146107965780638da5cb5b146107af5780638f1d3776146107cc575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa146107195780636c578c1d14610744578063715018a614610763578063728cdbca14610777575f80fd5b80635f77cf1d1461068f57806361267290146106db57806367caa37a146106fa575f80fd5b806341f756da1161026e57806341f756da146105d457806357e0af6c146105e75780635c975abb146106065780635ef7a94a1461061d575f80fd5b80632b7ac3f3146105695780633b70c18a146105a05780633e001b66146105bf575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004614ed4565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004614f01565b610b68565b005b3480156103fb575f80fd5b506103ee61040a366004614f5f565b610c3a565b34801561041a575f80fd5b50610397610429366004614ed4565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004614fa7565b610f76565b348015610470575f80fd5b506103ee61047f366004614ff6565b611493565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004614ed4565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004614ed4565b611852565b3480156104f3575f80fd5b506103c1610502366004614ed4565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004614ed4565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004614ed4565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c54610588906001600160a01b031681565b6040516001600160a01b0390911681526020016103a3565b3480156105ab575f80fd5b50609b54610588906001600160a01b031681565b3480156105ca575f80fd5b506103c160aa5481565b6103ee6105e2366004615084565b611880565b3480156105f2575f80fd5b506103ee610601366004614ed4565b611b84565b348015610611575f80fd5b5060655460ff16610397565b348015610628575f80fd5b50610666610637366004614ed4565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103a3565b34801561069a575f80fd5b506106c27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b3480156106e6575f80fd5b506103ee6106f5366004614ed4565b611c2f565b348015610705575f80fd5b506103ee610714366004615084565b611e0a565b348015610724575f80fd5b506103c1610733366004614ed4565b60ab6020525f908152604090205481565b34801561074f575f80fd5b506103ee61075e366004614f01565b612155565b34801561076e575f80fd5b506103ee612212565b348015610782575f80fd5b506103ee6107913660046150be565b612225565b3480156107a1575f80fd5b5060a6546103979060ff1681565b3480156107ba575f80fd5b506033546001600160a01b0316610588565b3480156107d7575f80fd5b506108386107e6366004614ed4565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b348015610887575f80fd5b50610397610896366004614ed4565b5f90815260a4602052604090206003015460ff1690565b3480156108b8575f80fd5b506103ee6108c7366004614f01565b61252e565b3480156108d7575f80fd5b50609754610588906001600160a01b031681565b3480156108f6575f80fd5b50610397610905366004614f01565b609f6020525f908152604090205460ff1681565b348015610924575f80fd5b506103c160995481565b348015610939575f80fd5b506103ee610948366004614ed4565b612611565b348015610958575f80fd5b506103c1610967366004614f01565b60a56020525f908152604090205481565b348015610983575f80fd5b506103c160a85481565b348015610998575f80fd5b506103ee6109a7366004615119565b6126c1565b3480156109b7575f80fd5b506103ee6109c6366004614f01565b6129ce565b3480156109d6575f80fd5b506103ee6109e5366004614fa7565b612a27565b3480156109f5575f80fd5b506103ee610a04366004615119565b612db8565b348015610a14575f80fd5b506103ee610a2336600461518d565b612e41565b348015610a33575f80fd5b506103ee610a42366004614ed4565b612f7f565b6103ee610a553660046151bf565b613022565b348015610a65575f80fd5b506103c160985481565b348015610a7a575f80fd5b506103ee610a89366004614ed4565b6135b4565b348015610a99575f80fd5b506103ee610aa8366004614f01565b613723565b348015610ab8575f80fd5b506103c160ac5481565b348015610acd575f80fd5b50610397610adc366004614ed4565b6137e2565b348015610aec575f80fd5b506103c1609a5481565b348015610b01575f80fd5b506103ee610b10366004614ed4565b61382c565b348015610b20575f80fd5b506103ee610b2f366004614f01565b6138cf565b348015610b3f575f80fd5b506103ee610b4e366004614f01565b61395c565b348015610b5e575f80fd5b506103c160a95481565b610b70613c0d565b6001600160a01b0381165f908152609f602052604090205460ff1615610bdd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c42613c0d565b5f8111610c915760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bd4565b5f80610c9d8585613c67565b915091505f610cb0836001015160c01c90565b5f81815260a160205260409020549091508214610d0f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f60a181610d1d8785615214565b81526020019081526020015f205414610d9d5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b609d548111610e145760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b610e1f600182615227565b609e555b8315610f6e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e6b816137e2565b15610ec6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610eb6908490615214565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f26575060a85481145b15610f30575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e23575b505050505050565b60a85415610fc65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b610fce613d0f565b5f80610fda8484613c67565b915091505f610fed836001015160c01c90565b5f81815260a16020526040902054909150821461104c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61105581611852565b6110a15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b6110aa816137e2565b156110f75760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a4602052604090206003015460ff16156111585760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bd4565b5f81815260a260205260409020600101544210156111b85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bd4565b605983015160a05f6111cb600185615227565b81526020019081526020015f2054146112265760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f81815260a06020526040902054156112815760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bd4565b80609d54600101146112d55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b609d819055600160a35f6112ea866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561133961132c846011015160c01c90565b600985015160c01c613d62565b60a25f611347600184615227565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113a39084615227565b81526020019081526020015f205f905560ad5f6001836113c39190615227565b81526020019081526020015f205f905560a45f6001836113e39190615227565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61146f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156114e35760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6114eb613d0f565b60ac54609e545f90815260a260205260408120549091429161150d9190615214565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611589919061523a565b6115939190615214565b109050811580156115a15750805b15611608575f6115b76080890160608a01615251565b61ffff16116116085760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b81806116115750805b61165d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bd4565b5f61167361166e60208a018a615272565b613c67565b5090505f611685826001015160c01c90565b611690906001615214565b5f81815260ad60205260408120549192509015611730575f491561171c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bd4565b505f81815260ad602052604090205461174b565b61174861174060208c018c6152d3565b60ff16613e19565b90505b6117568a5f83613f54565b5f806117628b8b613c67565b915091505f611775836001015160c01c90565b905080609e54146117c85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146118245760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f81815260a26020526040902042600190910155611843838b8b6144aa565b50505050505050505050505050565b5f81815260a260205260408120541580159061187a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191091906152f3565b61195c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a854156119ac5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6119b4613d0f565b5f6119c561166e6020840184615272565b5090505f6119d7826001015160c01c90565b6119e2906001615214565b5f81815260ad602052604090205490915015611a665760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aee919061523a565b611af89190615214565b1015611b60575f611b0f6080850160608601615251565b61ffff1611611b605760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b5f611b7161174060208601866152d3565b9050611b7e843383613f54565b50505050565b611b8c613c0d565b5f81118015611b9d57506099548114155b611be95760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bd4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c4f57505f5460ff8083169116105b611cc15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff831617610100179055611cdf5f5460ff1690565b60ff16600214611d315760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bd4565b81611da45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bd4565b609e545f90815260ab6020526040902054611dcd57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e9a91906152f3565b611ee65760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a85415611f365760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b611f3e613d0f565b5f4915611f8d5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bd4565b5f611f9e61166e6020840184615272565b5090505f611fb0826001015160c01c90565b611fbb906001615214565b5f81815260ad602052604090205490915061203e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120c6919061523a565b6120d09190615214565b1015612138575f6120e76080850160608601615251565b61ffff16116121385760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b61215083335f84815260ad6020526040902054613f54565b505050565b61215d613c0d565b6001600160a01b0381165f908152609f602052604090205460ff166121c45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bd4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c2f565b61221a613c0d565b6122235f61465d565b565b5f54610100900460ff161580801561224357505f54600160ff909116105b8061225c5750303b15801561225c57505f5460ff166001145b6122ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805460ff1916600117905580156122ef575f805461ff0019166101001790555b6001600160a01b038616158061230c57506001600160a01b038516155b15612343576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123995760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bd4565b6123a16146c6565b6123a961474a565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612525575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612536613c0d565b6001600160a01b0381161580159061255c5750609c546001600160a01b03828116911614155b6125a85760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bd4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612619613c0d565b5f81118015612629575060648111155b8015612637575060a9548114155b6126835760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bd4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c23565b60a854156127115760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b612719613d0f565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612785573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127a991906152f3565b6127f55760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b5f806128018686613c67565b915091505f612814836001015160c01c90565b5f81815260a1602052604090205490915082146128735760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61287c816137e2565b6128c85760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff19169055609954600290910154429161290491615214565b11612983575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f7574000000000000000000000000000000000000000000000000009183019190915261297e9183916001600160a01b0316906147ce565b612525565b61298e8386866144aa565b61252581336040518060400160405280600d81526020017f50726f6f6620737563636573730000000000000000000000000000000000000081525061492d565b6129d6613c0d565b60aa80545f9091556129e882826149f9565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c23565b612a2f613c0d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612aa65760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bd4565b5f80612ab28484613c67565b915091505f612ac5836001015160c01c90565b90508015612b155760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bd4565b5f612b21846079015190565b905080612b705760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bd4565b600984015160c01c15612bc55760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bd4565b5f612bd1856019015190565b03612c1e5760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bd4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c4a856039015190565b14612c975760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bd4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612dc48686613c67565b915091505f612dd7836001015160c01c90565b5f81815260a160205260409020549091508214612e365760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6125258386866144aa565b612e49613c0d565b8015612f4d57612e57614aa2565b60a65460ff1615612f0c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612eab908490615214565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f55614afc565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f2f565b50565b612f87613c0d565b5f81118015612f98575060ac548114155b612fe45760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bd4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c23565b335f908152609f602052604090205460ff166130805760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bd4565b60a854156130d05760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6130d8613d0f565b60a65460ff161561312b5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bd4565b8167ffffffffffffffff16609d54106131865760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a1602052604090205481146131ed5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6132008267ffffffffffffffff16611852565b61324c5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132c75760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133575760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bd4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133cb919061523a565b34101561341a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161353291815260200190565b60405180910390a35f609d54600161354a9190615214565b90505b609e5481116135a2578267ffffffffffffffff168114613590576099545f82815260a260205260408120600101805490919061358a908490615214565b90915550505b8061359a8161530e565b91505061354d565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135d457505f5460ff8083169116105b6136465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001781558290036136a85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bd4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b335f90815260a56020526040812054908190036137825760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bd4565b335f90815260a5602052604081205561379b82826149f9565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137d691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061187a5750505f90815260a46020526040902060030154610100900460ff161590565b613834613c0d565b5f8111801561384557506098548114155b6138915760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bd4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c23565b6138d7613c0d565b6001600160a01b0381166139535760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bd4565b612f7c8161465d565b5f54600490610100900460ff1615801561397c57505f5460ff8083169116105b6139ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001790556001600160a01b03821615801590613a2257505f826001600160a01b03163b115b613a6e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bd4565b609d54609e5414613ac15760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610bd4565b60a65460ff1615613b145760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bd4565b60a85415613b645760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6097546040516001600160a01b038085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6033546001600160a01b031633146122235760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bd4565b5f805f613c748585614b35565b90505f8160ff165f03613c9557613c8b8686614ba5565b9094509050613d01565b8160ff1660011480613caa57508160ff166002145b15613cb957613c8b8686614c0e565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bd4565b808420925050509250929050565b60655460ff16156122235760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bd4565b805f03613d6d575050565b8082035f5b82811015611b7e57610100818403811115613d8c57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613def575f80fd5b505af1158015613e01573d5f803e3d5ffd5b50505050610100830192505061010081019050613d72565b5f81600203613ea8575f6040515f5b804980613e355750613e44565b60208202830152600101613e28565b602081028083209201604052909250905080613ea25760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bd4565b50919050565b60014915613f1e5760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bd4565b5f4915613f2c575f4961187a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002613f6360208501856152d3565b60ff161115613fb45760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bd4565b60808301356140055760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bd4565b60a08301356140565760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bd4565b5f8061406861166e6020870187615272565b915091505f61407b836001015160c01c90565b90505f60a18161408c846001615214565b81526020019081526020015f2054146140e75760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bd4565b609e5481146141385760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146141945760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bd4565b5f81815260ab60205260409020546080870135146141f45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f614203846011015160c01c90565b90505f61422f61421960608a0160408b01615345565b61422960808b0160608c01615251565b84614c61565b90506142416080890160608a01615251565b60019384019361ffff91909116929092019160f99061426360208b018b6152d3565b60ff161061427057506101015b6040805182810190915295506142958661428d60208c018c6152d3565b60ff16614ca5565b60c084901b60018701526142c3866142b360808c0160608d01615251565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161431360208b018b6152d3565b60ff1610614345576143458661432f60608c0160408d01615345565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156143ae5760a7545f90815260a4602052604090206002015460995442916143a191615214565b6143ab9190615227565b90505b604051806080016040528042815260200182609854426143ce9190615214565b6143d89190615214565b81526020016143ed60608d0160408e01615345565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806144f75760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bd4565b5f614506846001015160c01c90565b90505f614514856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614543876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a848614605885160f81c90565b858888866040518663ffffffff1660e01b815260040161462995949392919061535e565b5f6040518083038186803b15801561463f575f80fd5b505afa158015614651573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147425760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614cac565b5f54610100900460ff166147c65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614d34565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614855573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614879919061523a565b5f86815260a46020526040902060010154909150614898908290615214565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906148d7908490615214565b90915550506040516148ea9084906153c1565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061495190846153ed565b61495b9190615404565b90506149678183615227565b60aa5f8282546149779190615214565b90915550506001600160a01b0384165f90815260a56020526040812080548392906149a3908490615214565b90915550506040516149b69084906153c1565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614a9e575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a48576040519150601f19603f3d011682016040523d82523d5f602084013e614a4d565b606091505b50509050806121505760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bd4565b5050565b614aaa613d0f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614adf3390565b6040516001600160a01b03909116815260200160405180910390a1565b614b04614db9565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614adf565b5f81614b835760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bd4565b82825f818110614b9557614b9561543c565b919091013560f81c949350505050565b5f8160f9811015614bf85760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bd4565b6040519150808483378082016040529250929050565b5f816101018114614bf85760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bd4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614c968161ffff871686614e0b565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614d285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6065805460ff19169055565b5f54610100900460ff16614db05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6122233361465d565b60655460ff166122235760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bd4565b5f825f03614e1a575082614ecd565b609b546001600160a01b03165f5b84811015614ec7576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614e8e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614eb2919061523a565b87525060209095019460019384019301614e28565b50849150505b9392505050565b5f60208284031215614ee4575f80fd5b5035919050565b80356001600160a01b0381168114613f4f575f80fd5b5f60208284031215614f11575f80fd5b614ecd82614eeb565b5f8083601f840112614f2a575f80fd5b50813567ffffffffffffffff811115614f41575f80fd5b602083019150836020828501011115614f58575f80fd5b9250929050565b5f805f60408486031215614f71575f80fd5b833567ffffffffffffffff811115614f87575f80fd5b614f9386828701614f1a565b909790965060209590950135949350505050565b5f8060208385031215614fb8575f80fd5b823567ffffffffffffffff811115614fce575f80fd5b614fda85828601614f1a565b90969095509350505050565b5f60e08284031215613ea2575f80fd5b5f805f805f6060868803121561500a575f80fd5b853567ffffffffffffffff80821115615021575f80fd5b61502d89838a01614fe6565b96506020880135915080821115615042575f80fd5b61504e89838a01614f1a565b90965094506040880135915080821115615066575f80fd5b5061507388828901614f1a565b969995985093965092949392505050565b5f60208284031215615094575f80fd5b813567ffffffffffffffff8111156150aa575f80fd5b6150b684828501614fe6565b949350505050565b5f805f805f8060c087890312156150d3575f80fd5b6150dc87614eeb565b95506150ea60208801614eeb565b94506150f860408801614eeb565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561512c575f80fd5b843567ffffffffffffffff80821115615143575f80fd5b61514f88838901614f1a565b90965094506020870135915080821115615167575f80fd5b5061517487828801614f1a565b95989497509550505050565b8015158114612f7c575f80fd5b5f6020828403121561519d575f80fd5b8135614ecd81615180565b803567ffffffffffffffff81168114613f4f575f80fd5b5f80604083850312156151d0575f80fd5b6151d9836151a8565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561187a5761187a6151e7565b8181038181111561187a5761187a6151e7565b5f6020828403121561524a575f80fd5b5051919050565b5f60208284031215615261575f80fd5b813561ffff81168114614ecd575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152a5575f80fd5b83018035915067ffffffffffffffff8211156152bf575f80fd5b602001915036819003821315614f58575f80fd5b5f602082840312156152e3575f80fd5b813560ff81168114614ecd575f80fd5b5f60208284031215615303575f80fd5b8151614ecd81615180565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361533e5761533e6151e7565b5060010190565b5f60208284031215615355575f80fd5b614ecd826151a8565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156153e057602081860181015185830152016153c6565b505f920191825250919050565b808202811582820484141761187a5761187a6151e7565b5f82615437577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a +0x608060405260043610610369575f3560e01c8063728cdbca116101c8578063b35dac4e116100fd578063cf9a67451161009d578063dff7827e1161006d578063dff7827e14610b20578063e3fff1dd14610b35578063f2fde38b14610b54578063fb1e8b0414610b73575f80fd5b8063cf9a674514610aae578063d279c19114610acd578063d8dc99d214610aec578063de8b303514610b01575f80fd5b8063bedb86fb116100d8578063bedb86fb14610a48578063c555389214610a67578063cd4edc6914610a86578063ce5db8d614610a99575f80fd5b8063b35dac4e146109eb578063b3e0a50914610a0a578063b8d0a1b014610a29575f80fd5b8063a3c9e94c11610168578063a4f209b011610143578063a4f209b01461096d578063abc8d68d1461098c578063b31a77d3146109b7578063b3484425146109cc575f80fd5b8063a3c9e94c1461090b578063a415d8dc1461092a578063a479265d14610958575f80fd5b80638da5cb5b116101a35780638da5cb5b146107ee5780638f1d37761461080b578063910129d4146108bb57806397fc007c146108ec575f80fd5b8063728cdbca14610797578063843bc9a1146107b657806388b1ea09146107d5575f80fd5b80632a213ba11161029e5780635ef7a94a1161023e57806367caa37a1161021957806367caa37a1461071a57806368589dfa146107395780636c578c1d14610764578063715018a614610783575f80fd5b80635ef7a94a1461063d5780635f77cf1d146106af57806361267290146106fb575f80fd5b80633e001b66116102795780633e001b66146105df57806341f756da146105f457806357e0af6c146106075780635c975abb14610626575f80fd5b80632a213ba11461055e5780632b7ac3f3146105895780633b70c18a146105c0575f80fd5b80631544ba3a1161030957806318af3b2b116102e457806318af3b2b146104b957806321e2f9e0146104e95780632362f03e146105085780632571098d14610533575f80fd5b80631544ba3a14610470578063163d9bee1461048f57806318463fb0146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e366004614f8a565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f4366004614fb7565b610b88565b005b348015610406575f80fd5b506103f9610415366004615015565b610c5a565b348015610425575f80fd5b506103a2610434366004614f8a565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b36600461505d565b610f96565b34801561047b575f80fd5b506103f961048a3660046150ac565b6114b3565b34801561049a575f80fd5b506103cc60ae5481565b3480156104af575f80fd5b506103cc60a75481565b3480156104c4575f80fd5b506103a26104d3366004614f8a565b5f90815260a26020526040902060010154421090565b3480156104f4575f80fd5b506103a2610503366004614f8a565b611872565b348015610513575f80fd5b506103cc610522366004614f8a565b60a16020525f908152604090205481565b34801561053e575f80fd5b506103cc61054d366004614f8a565b60a06020525f908152604090205481565b348015610569575f80fd5b506103cc610578366004614f8a565b60ad6020525f908152604090205481565b348015610594575f80fd5b50609c546105a8906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105cb575f80fd5b50609b546105a8906001600160a01b031681565b3480156105ea575f80fd5b506103cc60aa5481565b6103f961060236600461513a565b6118a0565b348015610612575f80fd5b506103f9610621366004614f8a565b611ba4565b348015610631575f80fd5b5060655460ff166103a2565b348015610648575f80fd5b50610686610657366004614f8a565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106ba575f80fd5b506106e27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b348015610706575f80fd5b506103f9610715366004614f8a565b611c4f565b348015610725575f80fd5b506103f961073436600461513a565b611e2a565b348015610744575f80fd5b506103cc610753366004614f8a565b60ab6020525f908152604090205481565b34801561076f575f80fd5b506103f961077e366004614fb7565b612175565b34801561078e575f80fd5b506103f9612232565b3480156107a2575f80fd5b506103f96107b1366004615174565b612245565b3480156107c1575f80fd5b506103f96107d03660046151cf565b61254e565b3480156107e0575f80fd5b5060a6546103a29060ff1681565b3480156107f9575f80fd5b506033546001600160a01b03166105a8565b348015610816575f80fd5b50610877610825366004614f8a565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108c6575f80fd5b506103a26108d5366004614f8a565b5f90815260a4602052604090206003015460ff1690565b3480156108f7575f80fd5b506103f9610906366004614fb7565b612895565b348015610916575f80fd5b506097546105a8906001600160a01b031681565b348015610935575f80fd5b506103a2610944366004614fb7565b609f6020525f908152604090205460ff1681565b348015610963575f80fd5b506103cc60995481565b348015610978575f80fd5b506103f9610987366004614f8a565b612978565b348015610997575f80fd5b506103cc6109a6366004614fb7565b60a56020525f908152604090205481565b3480156109c2575f80fd5b506103cc60a85481565b3480156109d7575f80fd5b506103f96109e63660046151f7565b612a28565b3480156109f6575f80fd5b506103f9610a05366004614fb7565b612d35565b348015610a15575f80fd5b506103f9610a2436600461505d565b612d8e565b348015610a34575f80fd5b506103f9610a433660046151f7565b61311f565b348015610a53575f80fd5b506103f9610a6236600461526b565b6131a8565b348015610a72575f80fd5b506103f9610a81366004614f8a565b6132e6565b6103f9610a9436600461529d565b613389565b348015610aa4575f80fd5b506103cc60985481565b348015610ab9575f80fd5b506103f9610ac8366004614f8a565b61391b565b348015610ad8575f80fd5b506103f9610ae7366004614fb7565b613a8a565b348015610af7575f80fd5b506103cc60ac5481565b348015610b0c575f80fd5b506103a2610b1b366004614f8a565b613b49565b348015610b2b575f80fd5b506103cc609a5481565b348015610b40575f80fd5b506103f9610b4f366004614f8a565b613b93565b348015610b5f575f80fd5b506103f9610b6e366004614fb7565b613c36565b348015610b7e575f80fd5b506103cc60a95481565b610b90613cc3565b6001600160a01b0381165f908152609f602052604090205460ff1615610bfd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c62613cc3565b5f8111610cb15760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bf4565b5f80610cbd8585613d1d565b915091505f610cd0836001015160c01c90565b5f81815260a160205260409020549091508214610d2f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f60a181610d3d87856152e4565b81526020019081526020015f205414610dbd5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b609d548111610e345760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b610e3f6001826152f7565b609e555b8315610f8e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e8b81613b49565b15610ee6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ed69084906152e4565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f46575060a85481145b15610f50575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e43575b505050505050565b60a85415610fe65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b610fee613dc5565b5f80610ffa8484613d1d565b915091505f61100d836001015160c01c90565b5f81815260a16020526040902054909150821461106c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b61107581611872565b6110c15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b6110ca81613b49565b156111175760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a4602052604090206003015460ff16156111785760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bf4565b5f81815260a260205260409020600101544210156111d85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bf4565b605983015160a05f6111eb6001856152f7565b81526020019081526020015f2054146112465760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f81815260a06020526040902054156112a15760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bf4565b80609d54600101146112f55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b609d819055600160a35f61130a866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561135961134c846011015160c01c90565b600985015160c01c613e18565b60a25f6113676001846152f7565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113c390846152f7565b81526020019081526020015f205f905560ad5f6001836113e391906152f7565b81526020019081526020015f205f905560a45f60018361140391906152f7565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61148f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156115035760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61150b613dc5565b60ac54609e545f90815260a260205260408120549091429161152d91906152e4565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a9919061530a565b6115b391906152e4565b109050811580156115c15750805b15611628575f6115d76080890160608a01615321565b61ffff16116116285760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b81806116315750805b61167d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bf4565b5f61169361168e60208a018a615342565b613d1d565b5090505f6116a5826001015160c01c90565b6116b09060016152e4565b5f81815260ad60205260408120549192509015611750575f491561173c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bf4565b505f81815260ad602052604090205461176b565b61176861176060208c018c6153a3565b60ff16613ecf565b90505b6117768a5f8361400a565b5f806117828b8b613d1d565b915091505f611795836001015160c01c90565b905080609e54146117e85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bf4565b5f81815260a1602052604090205482146118445760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f81815260a26020526040902042600190910155611863838b8b614560565b50505050505050505050505050565b5f81815260a260205260408120541580159061189a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561190c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061193091906153c3565b61197c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a854156119cc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b6119d4613dc5565b5f6119e561168e6020840184615342565b5090505f6119f7826001015160c01c90565b611a029060016152e4565b5f81815260ad602052604090205490915015611a865760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0e919061530a565b611b1891906152e4565b1015611b80575f611b2f6080850160608601615321565b61ffff1611611b805760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b5f611b9161176060208601866153a3565b9050611b9e84338361400a565b50505050565b611bac613cc3565b5f81118015611bbd57506099548114155b611c095760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bf4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c6f57505f5460ff8083169116105b611ce15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100179055611cff5f5460ff1690565b60ff16600214611d515760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bf4565b81611dc45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bf4565b609e545f90815260ab6020526040902054611ded57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eba91906153c3565b611f065760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a85415611f565760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b611f5e613dc5565b5f4915611fad5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bf4565b5f611fbe61168e6020840184615342565b5090505f611fd0826001015160c01c90565b611fdb9060016152e4565b5f81815260ad602052604090205490915061205e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120e6919061530a565b6120f091906152e4565b1015612158575f6121076080850160608601615321565b61ffff16116121585760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b61217083335f84815260ad602052604090205461400a565b505050565b61217d613cc3565b6001600160a01b0381165f908152609f602052604090205460ff166121e45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bf4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c4f565b61223a613cc3565b6122435f614713565b565b5f54610100900460ff161580801561226357505f54600160ff909116105b8061227c5750303b15801561227c57505f5460ff166001145b6122ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805460ff19166001179055801561230f575f805461ff0019166101001790555b6001600160a01b038616158061232c57506001600160a01b038516155b15612363576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123b95760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bf4565b6123c161477c565b6123c9614800565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612545575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b5f54600490610100900460ff1615801561256e57505f5460ff8083169116105b6125e05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff83161761010017905561261b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b6001600160a01b0316336001600160a01b03161461267b5760405162461bcd60e51b815260206004820152601060248201527f6f6e6c792070726f78792061646d696e000000000000000000000000000000006044820152606401610bf4565b6001600160a01b0383161580159061269c57505f836001600160a01b03163b115b6126e85760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bf4565b81609e54146127395760405162461bcd60e51b815260206004820152601660248201527f6375746f766572206261746368206d69736d61746368000000000000000000006044820152606401610bf4565b60a65460ff161561278c5760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bf4565b60a854156127dc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b60ae82905560975460405183916001600160a01b03808716929116907faf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935905f90a4609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b61289d613cc3565b6001600160a01b038116158015906128c35750609c546001600160a01b03828116911614155b61290f5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bf4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612980613cc3565b5f81118015612990575060648111155b801561299e575060a9548114155b6129ea5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bf4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c43565b60a85415612a785760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b612a80613dc5565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612aec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b1091906153c3565b612b5c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b5f80612b688686613d1d565b915091505f612b7b836001015160c01c90565b5f81815260a160205260409020549091508214612bda5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612be381613b49565b612c2f5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff191690556099546002909101544291612c6b916152e4565b11612cea575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612ce59183916001600160a01b031690614884565b612545565b612cf5838686614560565b61254581336040518060400160405280600d81526020017f50726f6f662073756363657373000000000000000000000000000000000000008152506149e3565b612d3d613cc3565b60aa80545f909155612d4f8282614aaf565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c43565b612d96613cc3565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612e0d5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bf4565b5f80612e198484613d1d565b915091505f612e2c836001015160c01c90565b90508015612e7c5760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bf4565b5f612e88846079015190565b905080612ed75760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bf4565b600984015160c01c15612f2c5760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bf4565b5f612f38856019015190565b03612f855760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bf4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612fb1856039015190565b14612ffe5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bf4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061312b8686613d1d565b915091505f61313e836001015160c01c90565b5f81815260a16020526040902054909150821461319d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612545838686614560565b6131b0613cc3565b80156132b4576131be614b58565b60a65460ff16156132735760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a590925282208054919290916132129084906152e4565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b6132bc614bb2565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613296565b50565b6132ee613cc3565b5f811180156132ff575060ac548114155b61334b5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bf4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c43565b335f908152609f602052604090205460ff166133e75760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bf4565b60a854156134375760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61343f613dc5565b60a65460ff16156134925760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bf4565b8167ffffffffffffffff16609d54106134ed5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a1602052604090205481146135545760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b6135678267ffffffffffffffff16611872565b6135b35760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b03161561362e5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106136be5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bf4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561370e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613732919061530a565b3410156137815760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161389991815260200190565b60405180910390a35f609d5460016138b191906152e4565b90505b609e548111613909578267ffffffffffffffff1681146138f7576099545f82815260a26020526040812060010180549091906138f19084906152e4565b90915550505b80613901816153de565b9150506138b4565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561393b57505f5460ff8083169116105b6139ad5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100178155829003613a0f5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bf4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b335f90815260a5602052604081205490819003613ae95760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bf4565b335f90815260a56020526040812055613b028282614aaf565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a82604051613b3d91815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061189a5750505f90815260a46020526040902060030154610100900460ff161590565b613b9b613cc3565b5f81118015613bac57506098548114155b613bf85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bf4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c43565b613c3e613cc3565b6001600160a01b038116613cba5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bf4565b6132e381614713565b6033546001600160a01b031633146122435760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bf4565b5f805f613d2a8585614beb565b90505f8160ff165f03613d4b57613d418686614c5b565b9094509050613db7565b8160ff1660011480613d6057508160ff166002145b15613d6f57613d418686614cc4565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bf4565b808420925050509250929050565b60655460ff16156122435760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bf4565b805f03613e23575050565b8082035f5b82811015611b9e57610100818403811115613e4257508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613ea5575f80fd5b505af1158015613eb7573d5f803e3d5ffd5b50505050610100830192505061010081019050613e28565b5f81600203613f5e575f6040515f5b804980613eeb5750613efa565b60208202830152600101613ede565b602081028083209201604052909250905080613f585760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bf4565b50919050565b60014915613fd45760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bf4565b5f4915613fe2575f4961189a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261401960208501856153a3565b60ff16111561406a5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bf4565b60808301356140bb5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bf4565b60a083013561410c5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bf4565b5f8061411e61168e6020870187615342565b915091505f614131836001015160c01c90565b90505f60a1816141428460016152e4565b81526020019081526020015f20541461419d5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bf4565b609e5481146141ee5760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b5f81815260a16020526040902054821461424a5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bf4565b5f81815260ab60205260409020546080870135146142aa5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f6142b9846011015160c01c90565b90505f6142e56142cf60608a0160408b01615415565b6142df60808b0160608c01615321565b84614d17565b90506142f76080890160608a01615321565b60019384019361ffff91909116929092019160f99061431960208b018b6153a3565b60ff161061432657506101015b60408051828101909152955061434b8661434360208c018c6153a3565b60ff16614d5b565b60c084901b60018701526143798661436960808c0160608d01615321565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d9860185905260016143c960208b018b6153a3565b60ff16106143fb576143fb866143e560608c0160408d01615415565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156144645760a7545f90815260a460205260409020600201546099544291614457916152e4565b61446191906152f7565b90505b6040518060800160405280428152602001826098544261448491906152e4565b61448e91906152e4565b81526020016144a360608d0160408e01615415565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806145ad5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bf4565b5f6145bc846001015160c01c90565b90505f6145ca856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006145f9876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486146bb885160f81c90565b858888866040518663ffffffff1660e01b81526004016146df95949392919061542e565b5f6040518083038186803b1580156146f5575f80fd5b505afa158015614707573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147f85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614d62565b5f54610100900460ff1661487c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614dea565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af115801561490b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061492f919061530a565b5f86815260a4602052604090206001015490915061494e9082906152e4565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a59091528120805490919061498d9084906152e4565b90915550506040516149a0908490615491565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614a0790846154bd565b614a1191906154d4565b9050614a1d81836152f7565b60aa5f828254614a2d91906152e4565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614a599084906152e4565b9091555050604051614a6c908490615491565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614b54575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614afe576040519150601f19603f3d011682016040523d82523d5f602084013e614b03565b606091505b50509050806121705760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bf4565b5050565b614b60613dc5565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614b953390565b6040516001600160a01b03909116815260200160405180910390a1565b614bba614e6f565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614b95565b5f81614c395760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bf4565b82825f818110614c4b57614c4b61550c565b919091013560f81c949350505050565b5f8160f9811015614cae5760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bf4565b6040519150808483378082016040529250929050565b5f816101018114614cae5760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bf4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614d4c8161ffff871686614ec1565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614dde5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b6065805460ff19169055565b5f54610100900460ff16614e665760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b61224333614713565b60655460ff166122435760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bf4565b5f825f03614ed0575082614f83565b609b546001600160a01b03165f5b84811015614f7d576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614f44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614f68919061530a565b87525060209095019460019384019301614ede565b50849150505b9392505050565b5f60208284031215614f9a575f80fd5b5035919050565b80356001600160a01b0381168114614005575f80fd5b5f60208284031215614fc7575f80fd5b614f8382614fa1565b5f8083601f840112614fe0575f80fd5b50813567ffffffffffffffff811115614ff7575f80fd5b60208301915083602082850101111561500e575f80fd5b9250929050565b5f805f60408486031215615027575f80fd5b833567ffffffffffffffff81111561503d575f80fd5b61504986828701614fd0565b909790965060209590950135949350505050565b5f806020838503121561506e575f80fd5b823567ffffffffffffffff811115615084575f80fd5b61509085828601614fd0565b90969095509350505050565b5f60e08284031215613f58575f80fd5b5f805f805f606086880312156150c0575f80fd5b853567ffffffffffffffff808211156150d7575f80fd5b6150e389838a0161509c565b965060208801359150808211156150f8575f80fd5b61510489838a01614fd0565b9096509450604088013591508082111561511c575f80fd5b5061512988828901614fd0565b969995985093965092949392505050565b5f6020828403121561514a575f80fd5b813567ffffffffffffffff811115615160575f80fd5b61516c8482850161509c565b949350505050565b5f805f805f8060c08789031215615189575f80fd5b61519287614fa1565b95506151a060208801614fa1565b94506151ae60408801614fa1565b9350606087013592506080870135915060a087013590509295509295509295565b5f80604083850312156151e0575f80fd5b6151e983614fa1565b946020939093013593505050565b5f805f806040858703121561520a575f80fd5b843567ffffffffffffffff80821115615221575f80fd5b61522d88838901614fd0565b90965094506020870135915080821115615245575f80fd5b5061525287828801614fd0565b95989497509550505050565b80151581146132e3575f80fd5b5f6020828403121561527b575f80fd5b8135614f838161525e565b803567ffffffffffffffff81168114614005575f80fd5b5f80604083850312156152ae575f80fd5b6151e983615286565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561189a5761189a6152b7565b8181038181111561189a5761189a6152b7565b5f6020828403121561531a575f80fd5b5051919050565b5f60208284031215615331575f80fd5b813561ffff81168114614f83575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615375575f80fd5b83018035915067ffffffffffffffff82111561538f575f80fd5b60200191503681900382131561500e575f80fd5b5f602082840312156153b3575f80fd5b813560ff81168114614f83575f80fd5b5f602082840312156153d3575f80fd5b8151614f838161525e565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361540e5761540e6152b7565b5060010190565b5f60208284031215615425575f80fd5b614f8382615286565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156154b05760208186018101518583015201615496565b505f920191825250919050565b808202811582820484141761189a5761189a6152b7565b5f82615507577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a diff --git a/bindings/bindings/centralization_cleanup_test.go b/bindings/bindings/centralization_cleanup_test.go index 3f9aa3dd7..1f7775ca3 100644 --- a/bindings/bindings/centralization_cleanup_test.go +++ b/bindings/bindings/centralization_cleanup_test.go @@ -22,7 +22,7 @@ func TestCurrentRollupBindingShape(t *testing.T) { "commitBatch": {selector: "41f756da", inputs: 1}, "commitState": {selector: "67caa37a", inputs: 1}, "commitBatchWithProof": {selector: "1544ba3a", inputs: 3}, - "initialize4": {selector: "f8fa010f", inputs: 1}, + "initialize4": {selector: "843bc9a1", inputs: 2}, } for name, want := range expected { method, ok := current.Methods[name] @@ -47,6 +47,15 @@ func TestCurrentRollupBindingShape(t *testing.T) { if _, ok := current.Methods["pendingBatchCount"]; ok { t.Fatal("generated Rollup binding must not contain pendingBatchCount") } + if method, ok := current.Methods["legacyCutoverBatchIndex"]; !ok || + len(method.Outputs) != 1 || method.Outputs[0].Type.String() != "uint256" { + t.Fatalf("generated Rollup binding has invalid legacyCutoverBatchIndex getter: %v", method) + } + cutoverEvent, ok := current.Events["SubmitterContractUpdated"] + if !ok || len(cutoverEvent.Inputs) != 3 || + !cutoverEvent.Inputs[2].Indexed || cutoverEvent.Inputs[2].Type.String() != "uint256" { + t.Fatalf("SubmitterContractUpdated must index the cutover batch: %v", cutoverEvent) + } } func TestCurrentSubmitterBindingShape(t *testing.T) { @@ -89,6 +98,7 @@ func TestCurrentStorageLayoutsAreGenerated(t *testing.T) { "submitterContract": 151, "batchDataStore": 162, "batchBlobVersionedHashes": 173, + "legacyCutoverBatchIndex": 174, } for _, entry := range RollupStorageLayout.Storage { if entry.Label == "pendingBatchCount" { diff --git a/bindings/bindings/rollup.go b/bindings/bindings/rollup.go index 832bffe8f..fc5a82fb1 100644 --- a/bindings/bindings/rollup.go +++ b/bindings/bindings/rollup.go @@ -42,8 +42,8 @@ type IRollupBatchDataInput struct { // RollupMetaData contains all meta data concerning the Rollup contract. var RollupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddr\",\"type\":\"address\"}],\"name\":\"SubmitterContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_submitterContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newSubmitter\",\"type\":\"address\"}],\"name\":\"initialize4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"submitterContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a060405234801562000010575f80fd5b50604051620055d4380380620055d483398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b6080516154766200015e5f395f81816106a0015261451901526154765ff3fe60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610af6578063f2fde38b14610b15578063f8fa010f14610b34578063fb1e8b0414610b53575f80fd5b8063d8dc99d214610aad578063de8b303514610ac2578063dff7827e14610ae1575f80fd5b8063cd4edc69116100cd578063cd4edc6914610a47578063ce5db8d614610a5a578063cf9a674514610a6f578063d279c19114610a8e575f80fd5b8063b8d0a1b0146109ea578063bedb86fb14610a09578063c555389214610a28575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d314610978578063b34844251461098d578063b35dac4e146109ac578063b3e0a509146109cb575f80fd5b8063a479265d14610919578063a4f209b01461092e578063abc8d68d1461094d575f80fd5b8063910129d411610198578063910129d41461087c57806397fc007c146108ad578063a3c9e94c146108cc578063a415d8dc146108eb575f80fd5b806388b1ea09146107965780638da5cb5b146107af5780638f1d3776146107cc575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa146107195780636c578c1d14610744578063715018a614610763578063728cdbca14610777575f80fd5b80635f77cf1d1461068f57806361267290146106db57806367caa37a146106fa575f80fd5b806341f756da1161026e57806341f756da146105d457806357e0af6c146105e75780635c975abb146106065780635ef7a94a1461061d575f80fd5b80632b7ac3f3146105695780633b70c18a146105a05780633e001b66146105bf575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004614ed4565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004614f01565b610b68565b005b3480156103fb575f80fd5b506103ee61040a366004614f5f565b610c3a565b34801561041a575f80fd5b50610397610429366004614ed4565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004614fa7565b610f76565b348015610470575f80fd5b506103ee61047f366004614ff6565b611493565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004614ed4565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004614ed4565b611852565b3480156104f3575f80fd5b506103c1610502366004614ed4565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004614ed4565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004614ed4565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c54610588906001600160a01b031681565b6040516001600160a01b0390911681526020016103a3565b3480156105ab575f80fd5b50609b54610588906001600160a01b031681565b3480156105ca575f80fd5b506103c160aa5481565b6103ee6105e2366004615084565b611880565b3480156105f2575f80fd5b506103ee610601366004614ed4565b611b84565b348015610611575f80fd5b5060655460ff16610397565b348015610628575f80fd5b50610666610637366004614ed4565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103a3565b34801561069a575f80fd5b506106c27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b3480156106e6575f80fd5b506103ee6106f5366004614ed4565b611c2f565b348015610705575f80fd5b506103ee610714366004615084565b611e0a565b348015610724575f80fd5b506103c1610733366004614ed4565b60ab6020525f908152604090205481565b34801561074f575f80fd5b506103ee61075e366004614f01565b612155565b34801561076e575f80fd5b506103ee612212565b348015610782575f80fd5b506103ee6107913660046150be565b612225565b3480156107a1575f80fd5b5060a6546103979060ff1681565b3480156107ba575f80fd5b506033546001600160a01b0316610588565b3480156107d7575f80fd5b506108386107e6366004614ed4565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b348015610887575f80fd5b50610397610896366004614ed4565b5f90815260a4602052604090206003015460ff1690565b3480156108b8575f80fd5b506103ee6108c7366004614f01565b61252e565b3480156108d7575f80fd5b50609754610588906001600160a01b031681565b3480156108f6575f80fd5b50610397610905366004614f01565b609f6020525f908152604090205460ff1681565b348015610924575f80fd5b506103c160995481565b348015610939575f80fd5b506103ee610948366004614ed4565b612611565b348015610958575f80fd5b506103c1610967366004614f01565b60a56020525f908152604090205481565b348015610983575f80fd5b506103c160a85481565b348015610998575f80fd5b506103ee6109a7366004615119565b6126c1565b3480156109b7575f80fd5b506103ee6109c6366004614f01565b6129ce565b3480156109d6575f80fd5b506103ee6109e5366004614fa7565b612a27565b3480156109f5575f80fd5b506103ee610a04366004615119565b612db8565b348015610a14575f80fd5b506103ee610a2336600461518d565b612e41565b348015610a33575f80fd5b506103ee610a42366004614ed4565b612f7f565b6103ee610a553660046151bf565b613022565b348015610a65575f80fd5b506103c160985481565b348015610a7a575f80fd5b506103ee610a89366004614ed4565b6135b4565b348015610a99575f80fd5b506103ee610aa8366004614f01565b613723565b348015610ab8575f80fd5b506103c160ac5481565b348015610acd575f80fd5b50610397610adc366004614ed4565b6137e2565b348015610aec575f80fd5b506103c1609a5481565b348015610b01575f80fd5b506103ee610b10366004614ed4565b61382c565b348015610b20575f80fd5b506103ee610b2f366004614f01565b6138cf565b348015610b3f575f80fd5b506103ee610b4e366004614f01565b61395c565b348015610b5e575f80fd5b506103c160a95481565b610b70613c0d565b6001600160a01b0381165f908152609f602052604090205460ff1615610bdd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c42613c0d565b5f8111610c915760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bd4565b5f80610c9d8585613c67565b915091505f610cb0836001015160c01c90565b5f81815260a160205260409020549091508214610d0f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f60a181610d1d8785615214565b81526020019081526020015f205414610d9d5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b609d548111610e145760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b610e1f600182615227565b609e555b8315610f6e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e6b816137e2565b15610ec6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610eb6908490615214565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f26575060a85481145b15610f30575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e23575b505050505050565b60a85415610fc65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b610fce613d0f565b5f80610fda8484613c67565b915091505f610fed836001015160c01c90565b5f81815260a16020526040902054909150821461104c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61105581611852565b6110a15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b6110aa816137e2565b156110f75760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a4602052604090206003015460ff16156111585760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bd4565b5f81815260a260205260409020600101544210156111b85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bd4565b605983015160a05f6111cb600185615227565b81526020019081526020015f2054146112265760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f81815260a06020526040902054156112815760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bd4565b80609d54600101146112d55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b609d819055600160a35f6112ea866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561133961132c846011015160c01c90565b600985015160c01c613d62565b60a25f611347600184615227565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113a39084615227565b81526020019081526020015f205f905560ad5f6001836113c39190615227565b81526020019081526020015f205f905560a45f6001836113e39190615227565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61146f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156114e35760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6114eb613d0f565b60ac54609e545f90815260a260205260408120549091429161150d9190615214565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611565573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611589919061523a565b6115939190615214565b109050811580156115a15750805b15611608575f6115b76080890160608a01615251565b61ffff16116116085760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b81806116115750805b61165d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bd4565b5f61167361166e60208a018a615272565b613c67565b5090505f611685826001015160c01c90565b611690906001615214565b5f81815260ad60205260408120549192509015611730575f491561171c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bd4565b505f81815260ad602052604090205461174b565b61174861174060208c018c6152d3565b60ff16613e19565b90505b6117568a5f83613f54565b5f806117628b8b613c67565b915091505f611775836001015160c01c90565b905080609e54146117c85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146118245760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b5f81815260a26020526040902042600190910155611843838b8b6144aa565b50505050505050505050505050565b5f81815260a260205260408120541580159061187a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191091906152f3565b61195c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a854156119ac5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6119b4613d0f565b5f6119c561166e6020840184615272565b5090505f6119d7826001015160c01c90565b6119e2906001615214565b5f81815260ad602052604090205490915015611a665760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aee919061523a565b611af89190615214565b1015611b60575f611b0f6080850160608601615251565b61ffff1611611b605760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b5f611b7161174060208601866152d3565b9050611b7e843383613f54565b50505050565b611b8c613c0d565b5f81118015611b9d57506099548114155b611be95760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bd4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c4f57505f5460ff8083169116105b611cc15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff831617610100179055611cdf5f5460ff1690565b60ff16600214611d315760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bd4565b81611da45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bd4565b609e545f90815260ab6020526040902054611dcd57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e9a91906152f3565b611ee65760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b60a85415611f365760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b611f3e613d0f565b5f4915611f8d5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bd4565b5f611f9e61166e6020840184615272565b5090505f611fb0826001015160c01c90565b611fbb906001615214565b5f81815260ad602052604090205490915061203e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bd4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120c6919061523a565b6120d09190615214565b1015612138575f6120e76080850160608601615251565b61ffff16116121385760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bd4565b61215083335f84815260ad6020526040902054613f54565b505050565b61215d613c0d565b6001600160a01b0381165f908152609f602052604090205460ff166121c45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bd4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c2f565b61221a613c0d565b6122235f61465d565b565b5f54610100900460ff161580801561224357505f54600160ff909116105b8061225c5750303b15801561225c57505f5460ff166001145b6122ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805460ff1916600117905580156122ef575f805461ff0019166101001790555b6001600160a01b038616158061230c57506001600160a01b038516155b15612343576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123995760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bd4565b6123a16146c6565b6123a961474a565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612525575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612536613c0d565b6001600160a01b0381161580159061255c5750609c546001600160a01b03828116911614155b6125a85760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bd4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612619613c0d565b5f81118015612629575060648111155b8015612637575060a9548114155b6126835760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bd4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c23565b60a854156127115760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b612719613d0f565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612785573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127a991906152f3565b6127f55760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bd4565b5f806128018686613c67565b915091505f612814836001015160c01c90565b5f81815260a1602052604090205490915082146128735760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b61287c816137e2565b6128c85760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bd4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff19169055609954600290910154429161290491615214565b11612983575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f7574000000000000000000000000000000000000000000000000009183019190915261297e9183916001600160a01b0316906147ce565b612525565b61298e8386866144aa565b61252581336040518060400160405280600d81526020017f50726f6f6620737563636573730000000000000000000000000000000000000081525061492d565b6129d6613c0d565b60aa80545f9091556129e882826149f9565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c23565b612a2f613c0d565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612aa65760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bd4565b5f80612ab28484613c67565b915091505f612ac5836001015160c01c90565b90508015612b155760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bd4565b5f612b21846079015190565b905080612b705760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bd4565b600984015160c01c15612bc55760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bd4565b5f612bd1856019015190565b03612c1e5760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bd4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612c4a856039015190565b14612c975760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bd4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f80612dc48686613c67565b915091505f612dd7836001015160c01c90565b5f81815260a160205260409020549091508214612e365760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6125258386866144aa565b612e49613c0d565b8015612f4d57612e57614aa2565b60a65460ff1615612f0c5760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091612eab908490615214565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b612f55614afc565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612f2f565b50565b612f87613c0d565b5f81118015612f98575060ac548114155b612fe45760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bd4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c23565b335f908152609f602052604090205460ff166130805760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bd4565b60a854156130d05760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6130d8613d0f565b60a65460ff161561312b5760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bd4565b8167ffffffffffffffff16609d54106131865760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a1602052604090205481146131ed5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bd4565b6132008267ffffffffffffffff16611852565b61324c5760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b0316156132c75760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bd4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106133575760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bd4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133cb919061523a565b34101561341a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bd4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161353291815260200190565b60405180910390a35f609d54600161354a9190615214565b90505b609e5481116135a2578267ffffffffffffffff168114613590576099545f82815260a260205260408120600101805490919061358a908490615214565b90915550505b8061359a8161530e565b91505061354d565b505060a6805460ff1916600117905550565b5f54600390610100900460ff161580156135d457505f5460ff8083169116105b6136465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001781558290036136a85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bd4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b335f90815260a56020526040812054908190036137825760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bd4565b335f90815260a5602052604081205561379b82826149f9565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516137d691815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061187a5750505f90815260a46020526040902060030154610100900460ff161590565b613834613c0d565b5f8111801561384557506098548114155b6138915760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bd4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c23565b6138d7613c0d565b6001600160a01b0381166139535760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bd4565b612f7c8161465d565b5f54600490610100900460ff1615801561397c57505f5460ff8083169116105b6139ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd4565b5f805461ffff191660ff8316176101001790556001600160a01b03821615801590613a2257505f826001600160a01b03163b115b613a6e5760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bd4565b609d54609e5414613ac15760405162461bcd60e51b815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610bd4565b60a65460ff1615613b145760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bd4565b60a85415613b645760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bd4565b6097546040516001600160a01b038085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c23565b6033546001600160a01b031633146122235760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bd4565b5f805f613c748585614b35565b90505f8160ff165f03613c9557613c8b8686614ba5565b9094509050613d01565b8160ff1660011480613caa57508160ff166002145b15613cb957613c8b8686614c0e565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bd4565b808420925050509250929050565b60655460ff16156122235760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bd4565b805f03613d6d575050565b8082035f5b82811015611b7e57610100818403811115613d8c57508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613def575f80fd5b505af1158015613e01573d5f803e3d5ffd5b50505050610100830192505061010081019050613d72565b5f81600203613ea8575f6040515f5b804980613e355750613e44565b60208202830152600101613e28565b602081028083209201604052909250905080613ea25760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bd4565b50919050565b60014915613f1e5760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bd4565b5f4915613f2c575f4961187a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002613f6360208501856152d3565b60ff161115613fb45760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bd4565b60808301356140055760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bd4565b60a08301356140565760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bd4565b5f8061406861166e6020870187615272565b915091505f61407b836001015160c01c90565b90505f60a18161408c846001615214565b81526020019081526020015f2054146140e75760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bd4565b609e5481146141385760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bd4565b5f81815260a1602052604090205482146141945760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bd4565b5f81815260ab60205260409020546080870135146141f45760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bd4565b5f614203846011015160c01c90565b90505f61422f61421960608a0160408b01615345565b61422960808b0160608c01615251565b84614c61565b90506142416080890160608a01615251565b60019384019361ffff91909116929092019160f99061426360208b018b6152d3565b60ff161061427057506101015b6040805182810190915295506142958661428d60208c018c6152d3565b60ff16614ca5565b60c084901b60018701526142c3866142b360808c0160608d01615251565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161431360208b018b6152d3565b60ff1610614345576143458661432f60608c0160408d01615345565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156143ae5760a7545f90815260a4602052604090206002015460995442916143a191615214565b6143ab9190615227565b90505b604051806080016040528042815260200182609854426143ce9190615214565b6143d89190615214565b81526020016143ed60608d0160408e01615345565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806144f75760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bd4565b5f614506846001015160c01c90565b90505f614514856039015190565b90505f7f0000000000000000000000000000000000000000000000000000000000000000614543876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a848614605885160f81c90565b858888866040518663ffffffff1660e01b815260040161462995949392919061535e565b5f6040518083038186803b15801561463f575f80fd5b505afa158015614651573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147425760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614cac565b5f54610100900460ff166147c65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b612223614d34565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af1158015614855573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614879919061523a565b5f86815260a46020526040902060010154909150614898908290615214565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a5909152812080549091906148d7908490615214565b90915550506040516148ea9084906153c1565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a95490919060649061495190846153ed565b61495b9190615404565b90506149678183615227565b60aa5f8282546149779190615214565b90915550506001600160a01b0384165f90815260a56020526040812080548392906149a3908490615214565b90915550506040516149b69084906153c1565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614a9e575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a48576040519150601f19603f3d011682016040523d82523d5f602084013e614a4d565b606091505b50509050806121505760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bd4565b5050565b614aaa613d0f565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614adf3390565b6040516001600160a01b03909116815260200160405180910390a1565b614b04614db9565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614adf565b5f81614b835760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bd4565b82825f818110614b9557614b9561543c565b919091013560f81c949350505050565b5f8160f9811015614bf85760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bd4565b6040519150808483378082016040529250929050565b5f816101018114614bf85760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bd4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614c968161ffff871686614e0b565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614d285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6065805460ff19169055565b5f54610100900460ff16614db05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd4565b6122233361465d565b60655460ff166122235760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bd4565b5f825f03614e1a575082614ecd565b609b546001600160a01b03165f5b84811015614ec7576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614e8e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614eb2919061523a565b87525060209095019460019384019301614e28565b50849150505b9392505050565b5f60208284031215614ee4575f80fd5b5035919050565b80356001600160a01b0381168114613f4f575f80fd5b5f60208284031215614f11575f80fd5b614ecd82614eeb565b5f8083601f840112614f2a575f80fd5b50813567ffffffffffffffff811115614f41575f80fd5b602083019150836020828501011115614f58575f80fd5b9250929050565b5f805f60408486031215614f71575f80fd5b833567ffffffffffffffff811115614f87575f80fd5b614f9386828701614f1a565b909790965060209590950135949350505050565b5f8060208385031215614fb8575f80fd5b823567ffffffffffffffff811115614fce575f80fd5b614fda85828601614f1a565b90969095509350505050565b5f60e08284031215613ea2575f80fd5b5f805f805f6060868803121561500a575f80fd5b853567ffffffffffffffff80821115615021575f80fd5b61502d89838a01614fe6565b96506020880135915080821115615042575f80fd5b61504e89838a01614f1a565b90965094506040880135915080821115615066575f80fd5b5061507388828901614f1a565b969995985093965092949392505050565b5f60208284031215615094575f80fd5b813567ffffffffffffffff8111156150aa575f80fd5b6150b684828501614fe6565b949350505050565b5f805f805f8060c087890312156150d3575f80fd5b6150dc87614eeb565b95506150ea60208801614eeb565b94506150f860408801614eeb565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561512c575f80fd5b843567ffffffffffffffff80821115615143575f80fd5b61514f88838901614f1a565b90965094506020870135915080821115615167575f80fd5b5061517487828801614f1a565b95989497509550505050565b8015158114612f7c575f80fd5b5f6020828403121561519d575f80fd5b8135614ecd81615180565b803567ffffffffffffffff81168114613f4f575f80fd5b5f80604083850312156151d0575f80fd5b6151d9836151a8565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561187a5761187a6151e7565b8181038181111561187a5761187a6151e7565b5f6020828403121561524a575f80fd5b5051919050565b5f60208284031215615261575f80fd5b813561ffff81168114614ecd575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152a5575f80fd5b83018035915067ffffffffffffffff8211156152bf575f80fd5b602001915036819003821315614f58575f80fd5b5f602082840312156152e3575f80fd5b813560ff81168114614ecd575f80fd5b5f60208284031215615303575f80fd5b8151614ecd81615180565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361533e5761533e6151e7565b5060010190565b5f60208284031215615355575f80fd5b614ecd826151a8565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156153e057602081860181015185830152016153c6565b505f920191825250919050565b808202811582820484141761187a5761187a6151e7565b5f82615437577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainID\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ErrZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"winner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"string\",\"name\":\"res\",\"type\":\"string\"}],\"name\":\"ChallengeRes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ChallengeRewardClaim\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"}],\"name\":\"ChallengeState\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"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\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProveRemainingClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"legacyCutoverBatchIndex\",\"type\":\"uint256\"}],\"name\":\"SubmitterContractUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateChallenger\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateFinalizationPeriodSeconds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPercent\",\"type\":\"uint256\"}],\"name\":\"UpdateProofRewardPercent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldWindow\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newWindow\",\"type\":\"uint256\"}],\"name\":\"UpdateProofWindow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldPeriod\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPeriod\",\"type\":\"uint256\"}],\"name\":\"UpdateRollupDelayPeriod\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LAYER_2_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__maxNumTxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"addChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchBlobVersionedHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"batchChallengeReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"batchChallenged\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchChallengedSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchDataStore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"originTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"finalizeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"submitter\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchExist\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"batchInsideChallengeWindow\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"_batchHash\",\"type\":\"bytes32\"}],\"name\":\"challengeState\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"challenges\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"challengeDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTime\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"challengeSuccess\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"finished\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimProveRemaining\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"claimReward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"commitBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"lastBlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"numL1Messages\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structIRollup.BatchDataInput\",\"name\":\"batchDataInput\",\"type\":\"tuple\"}],\"name\":\"commitState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizationPeriodSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"finalizeBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inChallenge\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_submitterContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_finalizationPeriodSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofWindow\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_proofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"}],\"name\":\"initialize2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_rollupDelayPeriod\",\"type\":\"uint256\"}],\"name\":\"initialize3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newSubmitter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_expectedLegacyCutoverBatchIndex\",\"type\":\"uint256\"}],\"name\":\"initialize4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"challengerAddress\",\"type\":\"address\"}],\"name\":\"isChallenger\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isChallenger\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastCommittedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"legacyCutoverBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofRewardPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proofWindow\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveCommittedBatchState\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proveRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_batchProof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"removeChallenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revertReqIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupDelayPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"setPause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"submitterContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateFinalizePeriodSeconds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newWindow\",\"type\":\"uint256\"}],\"name\":\"updateProofWindow\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newProofRewardPercent\",\"type\":\"uint256\"}],\"name\":\"updateRewardPercentage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newPeriod\",\"type\":\"uint256\"}],\"name\":\"updateRollupDelayPeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"}],\"name\":\"withdrawalRoots\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exist\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60a060405234801562000010575f80fd5b50604051620056a4380380620056a483398101604081905262000033916200010f565b6001600160401b0381166080526200004a62000051565b506200013e565b5f54610100900460ff1615620000bd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116146200010d575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f6020828403121562000120575f80fd5b81516001600160401b038116811462000137575f80fd5b9392505050565b6080516155466200015e5f395f81816106c001526145cf01526155465ff3fe608060405260043610610369575f3560e01c8063728cdbca116101c8578063b35dac4e116100fd578063cf9a67451161009d578063dff7827e1161006d578063dff7827e14610b20578063e3fff1dd14610b35578063f2fde38b14610b54578063fb1e8b0414610b73575f80fd5b8063cf9a674514610aae578063d279c19114610acd578063d8dc99d214610aec578063de8b303514610b01575f80fd5b8063bedb86fb116100d8578063bedb86fb14610a48578063c555389214610a67578063cd4edc6914610a86578063ce5db8d614610a99575f80fd5b8063b35dac4e146109eb578063b3e0a50914610a0a578063b8d0a1b014610a29575f80fd5b8063a3c9e94c11610168578063a4f209b011610143578063a4f209b01461096d578063abc8d68d1461098c578063b31a77d3146109b7578063b3484425146109cc575f80fd5b8063a3c9e94c1461090b578063a415d8dc1461092a578063a479265d14610958575f80fd5b80638da5cb5b116101a35780638da5cb5b146107ee5780638f1d37761461080b578063910129d4146108bb57806397fc007c146108ec575f80fd5b8063728cdbca14610797578063843bc9a1146107b657806388b1ea09146107d5575f80fd5b80632a213ba11161029e5780635ef7a94a1161023e57806367caa37a1161021957806367caa37a1461071a57806368589dfa146107395780636c578c1d14610764578063715018a614610783575f80fd5b80635ef7a94a1461063d5780635f77cf1d146106af57806361267290146106fb575f80fd5b80633e001b66116102795780633e001b66146105df57806341f756da146105f457806357e0af6c146106075780635c975abb14610626575f80fd5b80632a213ba11461055e5780632b7ac3f3146105895780633b70c18a146105c0575f80fd5b80631544ba3a1161030957806318af3b2b116102e457806318af3b2b146104b957806321e2f9e0146104e95780632362f03e146105085780632571098d14610533575f80fd5b80631544ba3a14610470578063163d9bee1461048f57806318463fb0146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e366004614f8a565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f4366004614fb7565b610b88565b005b348015610406575f80fd5b506103f9610415366004615015565b610c5a565b348015610425575f80fd5b506103a2610434366004614f8a565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b36600461505d565b610f96565b34801561047b575f80fd5b506103f961048a3660046150ac565b6114b3565b34801561049a575f80fd5b506103cc60ae5481565b3480156104af575f80fd5b506103cc60a75481565b3480156104c4575f80fd5b506103a26104d3366004614f8a565b5f90815260a26020526040902060010154421090565b3480156104f4575f80fd5b506103a2610503366004614f8a565b611872565b348015610513575f80fd5b506103cc610522366004614f8a565b60a16020525f908152604090205481565b34801561053e575f80fd5b506103cc61054d366004614f8a565b60a06020525f908152604090205481565b348015610569575f80fd5b506103cc610578366004614f8a565b60ad6020525f908152604090205481565b348015610594575f80fd5b50609c546105a8906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105cb575f80fd5b50609b546105a8906001600160a01b031681565b3480156105ea575f80fd5b506103cc60aa5481565b6103f961060236600461513a565b6118a0565b348015610612575f80fd5b506103f9610621366004614f8a565b611ba4565b348015610631575f80fd5b5060655460ff166103a2565b348015610648575f80fd5b50610686610657366004614f8a565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106ba575f80fd5b506106e27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b348015610706575f80fd5b506103f9610715366004614f8a565b611c4f565b348015610725575f80fd5b506103f961073436600461513a565b611e2a565b348015610744575f80fd5b506103cc610753366004614f8a565b60ab6020525f908152604090205481565b34801561076f575f80fd5b506103f961077e366004614fb7565b612175565b34801561078e575f80fd5b506103f9612232565b3480156107a2575f80fd5b506103f96107b1366004615174565b612245565b3480156107c1575f80fd5b506103f96107d03660046151cf565b61254e565b3480156107e0575f80fd5b5060a6546103a29060ff1681565b3480156107f9575f80fd5b506033546001600160a01b03166105a8565b348015610816575f80fd5b50610877610825366004614f8a565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108c6575f80fd5b506103a26108d5366004614f8a565b5f90815260a4602052604090206003015460ff1690565b3480156108f7575f80fd5b506103f9610906366004614fb7565b612895565b348015610916575f80fd5b506097546105a8906001600160a01b031681565b348015610935575f80fd5b506103a2610944366004614fb7565b609f6020525f908152604090205460ff1681565b348015610963575f80fd5b506103cc60995481565b348015610978575f80fd5b506103f9610987366004614f8a565b612978565b348015610997575f80fd5b506103cc6109a6366004614fb7565b60a56020525f908152604090205481565b3480156109c2575f80fd5b506103cc60a85481565b3480156109d7575f80fd5b506103f96109e63660046151f7565b612a28565b3480156109f6575f80fd5b506103f9610a05366004614fb7565b612d35565b348015610a15575f80fd5b506103f9610a2436600461505d565b612d8e565b348015610a34575f80fd5b506103f9610a433660046151f7565b61311f565b348015610a53575f80fd5b506103f9610a6236600461526b565b6131a8565b348015610a72575f80fd5b506103f9610a81366004614f8a565b6132e6565b6103f9610a9436600461529d565b613389565b348015610aa4575f80fd5b506103cc60985481565b348015610ab9575f80fd5b506103f9610ac8366004614f8a565b61391b565b348015610ad8575f80fd5b506103f9610ae7366004614fb7565b613a8a565b348015610af7575f80fd5b506103cc60ac5481565b348015610b0c575f80fd5b506103a2610b1b366004614f8a565b613b49565b348015610b2b575f80fd5b506103cc609a5481565b348015610b40575f80fd5b506103f9610b4f366004614f8a565b613b93565b348015610b5f575f80fd5b506103f9610b6e366004614fb7565b613c36565b348015610b7e575f80fd5b506103cc60a95481565b610b90613cc3565b6001600160a01b0381165f908152609f602052604090205460ff1615610bfd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c62613cc3565b5f8111610cb15760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bf4565b5f80610cbd8585613d1d565b915091505f610cd0836001015160c01c90565b5f81815260a160205260409020549091508214610d2f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f60a181610d3d87856152e4565b81526020019081526020015f205414610dbd5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b609d548111610e345760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b610e3f6001826152f7565b609e555b8315610f8e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e8b81613b49565b15610ee6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ed69084906152e4565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f46575060a85481145b15610f50575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e43575b505050505050565b60a85415610fe65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b610fee613dc5565b5f80610ffa8484613d1d565b915091505f61100d836001015160c01c90565b5f81815260a16020526040902054909150821461106c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b61107581611872565b6110c15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b6110ca81613b49565b156111175760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a4602052604090206003015460ff16156111785760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bf4565b5f81815260a260205260409020600101544210156111d85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bf4565b605983015160a05f6111eb6001856152f7565b81526020019081526020015f2054146112465760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f81815260a06020526040902054156112a15760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bf4565b80609d54600101146112f55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b609d819055600160a35f61130a866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561135961134c846011015160c01c90565b600985015160c01c613e18565b60a25f6113676001846152f7565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113c390846152f7565b81526020019081526020015f205f905560ad5f6001836113e391906152f7565b81526020019081526020015f205f905560a45f60018361140391906152f7565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61148f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156115035760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61150b613dc5565b60ac54609e545f90815260a260205260408120549091429161152d91906152e4565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a9919061530a565b6115b391906152e4565b109050811580156115c15750805b15611628575f6115d76080890160608a01615321565b61ffff16116116285760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b81806116315750805b61167d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bf4565b5f61169361168e60208a018a615342565b613d1d565b5090505f6116a5826001015160c01c90565b6116b09060016152e4565b5f81815260ad60205260408120549192509015611750575f491561173c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bf4565b505f81815260ad602052604090205461176b565b61176861176060208c018c6153a3565b60ff16613ecf565b90505b6117768a5f8361400a565b5f806117828b8b613d1d565b915091505f611795836001015160c01c90565b905080609e54146117e85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bf4565b5f81815260a1602052604090205482146118445760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f81815260a26020526040902042600190910155611863838b8b614560565b50505050505050505050505050565b5f81815260a260205260408120541580159061189a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561190c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061193091906153c3565b61197c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a854156119cc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b6119d4613dc5565b5f6119e561168e6020840184615342565b5090505f6119f7826001015160c01c90565b611a029060016152e4565b5f81815260ad602052604090205490915015611a865760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0e919061530a565b611b1891906152e4565b1015611b80575f611b2f6080850160608601615321565b61ffff1611611b805760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b5f611b9161176060208601866153a3565b9050611b9e84338361400a565b50505050565b611bac613cc3565b5f81118015611bbd57506099548114155b611c095760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bf4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c6f57505f5460ff8083169116105b611ce15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100179055611cff5f5460ff1690565b60ff16600214611d515760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bf4565b81611dc45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bf4565b609e545f90815260ab6020526040902054611ded57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eba91906153c3565b611f065760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a85415611f565760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b611f5e613dc5565b5f4915611fad5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bf4565b5f611fbe61168e6020840184615342565b5090505f611fd0826001015160c01c90565b611fdb9060016152e4565b5f81815260ad602052604090205490915061205e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120e6919061530a565b6120f091906152e4565b1015612158575f6121076080850160608601615321565b61ffff16116121585760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b61217083335f84815260ad602052604090205461400a565b505050565b61217d613cc3565b6001600160a01b0381165f908152609f602052604090205460ff166121e45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bf4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c4f565b61223a613cc3565b6122435f614713565b565b5f54610100900460ff161580801561226357505f54600160ff909116105b8061227c5750303b15801561227c57505f5460ff166001145b6122ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805460ff19166001179055801561230f575f805461ff0019166101001790555b6001600160a01b038616158061232c57506001600160a01b038516155b15612363576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123b95760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bf4565b6123c161477c565b6123c9614800565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612545575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b5f54600490610100900460ff1615801561256e57505f5460ff8083169116105b6125e05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff83161761010017905561261b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b6001600160a01b0316336001600160a01b03161461267b5760405162461bcd60e51b815260206004820152601060248201527f6f6e6c792070726f78792061646d696e000000000000000000000000000000006044820152606401610bf4565b6001600160a01b0383161580159061269c57505f836001600160a01b03163b115b6126e85760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bf4565b81609e54146127395760405162461bcd60e51b815260206004820152601660248201527f6375746f766572206261746368206d69736d61746368000000000000000000006044820152606401610bf4565b60a65460ff161561278c5760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bf4565b60a854156127dc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b60ae82905560975460405183916001600160a01b03808716929116907faf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935905f90a4609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b61289d613cc3565b6001600160a01b038116158015906128c35750609c546001600160a01b03828116911614155b61290f5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bf4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612980613cc3565b5f81118015612990575060648111155b801561299e575060a9548114155b6129ea5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bf4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c43565b60a85415612a785760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b612a80613dc5565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612aec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b1091906153c3565b612b5c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b5f80612b688686613d1d565b915091505f612b7b836001015160c01c90565b5f81815260a160205260409020549091508214612bda5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612be381613b49565b612c2f5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff191690556099546002909101544291612c6b916152e4565b11612cea575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612ce59183916001600160a01b031690614884565b612545565b612cf5838686614560565b61254581336040518060400160405280600d81526020017f50726f6f662073756363657373000000000000000000000000000000000000008152506149e3565b612d3d613cc3565b60aa80545f909155612d4f8282614aaf565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c43565b612d96613cc3565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612e0d5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bf4565b5f80612e198484613d1d565b915091505f612e2c836001015160c01c90565b90508015612e7c5760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bf4565b5f612e88846079015190565b905080612ed75760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bf4565b600984015160c01c15612f2c5760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bf4565b5f612f38856019015190565b03612f855760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bf4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612fb1856039015190565b14612ffe5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bf4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061312b8686613d1d565b915091505f61313e836001015160c01c90565b5f81815260a16020526040902054909150821461319d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612545838686614560565b6131b0613cc3565b80156132b4576131be614b58565b60a65460ff16156132735760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a590925282208054919290916132129084906152e4565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b6132bc614bb2565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613296565b50565b6132ee613cc3565b5f811180156132ff575060ac548114155b61334b5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bf4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c43565b335f908152609f602052604090205460ff166133e75760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bf4565b60a854156134375760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61343f613dc5565b60a65460ff16156134925760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bf4565b8167ffffffffffffffff16609d54106134ed5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a1602052604090205481146135545760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b6135678267ffffffffffffffff16611872565b6135b35760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b03161561362e5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106136be5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bf4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561370e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613732919061530a565b3410156137815760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161389991815260200190565b60405180910390a35f609d5460016138b191906152e4565b90505b609e548111613909578267ffffffffffffffff1681146138f7576099545f82815260a26020526040812060010180549091906138f19084906152e4565b90915550505b80613901816153de565b9150506138b4565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561393b57505f5460ff8083169116105b6139ad5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100178155829003613a0f5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bf4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b335f90815260a5602052604081205490819003613ae95760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bf4565b335f90815260a56020526040812055613b028282614aaf565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a82604051613b3d91815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061189a5750505f90815260a46020526040902060030154610100900460ff161590565b613b9b613cc3565b5f81118015613bac57506098548114155b613bf85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bf4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c43565b613c3e613cc3565b6001600160a01b038116613cba5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bf4565b6132e381614713565b6033546001600160a01b031633146122435760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bf4565b5f805f613d2a8585614beb565b90505f8160ff165f03613d4b57613d418686614c5b565b9094509050613db7565b8160ff1660011480613d6057508160ff166002145b15613d6f57613d418686614cc4565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bf4565b808420925050509250929050565b60655460ff16156122435760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bf4565b805f03613e23575050565b8082035f5b82811015611b9e57610100818403811115613e4257508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613ea5575f80fd5b505af1158015613eb7573d5f803e3d5ffd5b50505050610100830192505061010081019050613e28565b5f81600203613f5e575f6040515f5b804980613eeb5750613efa565b60208202830152600101613ede565b602081028083209201604052909250905080613f585760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bf4565b50919050565b60014915613fd45760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bf4565b5f4915613fe2575f4961189a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261401960208501856153a3565b60ff16111561406a5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bf4565b60808301356140bb5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bf4565b60a083013561410c5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bf4565b5f8061411e61168e6020870187615342565b915091505f614131836001015160c01c90565b90505f60a1816141428460016152e4565b81526020019081526020015f20541461419d5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bf4565b609e5481146141ee5760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b5f81815260a16020526040902054821461424a5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bf4565b5f81815260ab60205260409020546080870135146142aa5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f6142b9846011015160c01c90565b90505f6142e56142cf60608a0160408b01615415565b6142df60808b0160608c01615321565b84614d17565b90506142f76080890160608a01615321565b60019384019361ffff91909116929092019160f99061431960208b018b6153a3565b60ff161061432657506101015b60408051828101909152955061434b8661434360208c018c6153a3565b60ff16614d5b565b60c084901b60018701526143798661436960808c0160608d01615321565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d9860185905260016143c960208b018b6153a3565b60ff16106143fb576143fb866143e560608c0160408d01615415565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156144645760a7545f90815260a460205260409020600201546099544291614457916152e4565b61446191906152f7565b90505b6040518060800160405280428152602001826098544261448491906152e4565b61448e91906152e4565b81526020016144a360608d0160408e01615415565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806145ad5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bf4565b5f6145bc846001015160c01c90565b90505f6145ca856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006145f9876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486146bb885160f81c90565b858888866040518663ffffffff1660e01b81526004016146df95949392919061542e565b5f6040518083038186803b1580156146f5575f80fd5b505afa158015614707573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147f85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614d62565b5f54610100900460ff1661487c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614dea565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af115801561490b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061492f919061530a565b5f86815260a4602052604090206001015490915061494e9082906152e4565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a59091528120805490919061498d9084906152e4565b90915550506040516149a0908490615491565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614a0790846154bd565b614a1191906154d4565b9050614a1d81836152f7565b60aa5f828254614a2d91906152e4565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614a599084906152e4565b9091555050604051614a6c908490615491565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614b54575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614afe576040519150601f19603f3d011682016040523d82523d5f602084013e614b03565b606091505b50509050806121705760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bf4565b5050565b614b60613dc5565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614b953390565b6040516001600160a01b03909116815260200160405180910390a1565b614bba614e6f565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614b95565b5f81614c395760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bf4565b82825f818110614c4b57614c4b61550c565b919091013560f81c949350505050565b5f8160f9811015614cae5760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bf4565b6040519150808483378082016040529250929050565b5f816101018114614cae5760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bf4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614d4c8161ffff871686614ec1565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614dde5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b6065805460ff19169055565b5f54610100900460ff16614e665760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b61224333614713565b60655460ff166122435760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bf4565b5f825f03614ed0575082614f83565b609b546001600160a01b03165f5b84811015614f7d576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614f44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614f68919061530a565b87525060209095019460019384019301614ede565b50849150505b9392505050565b5f60208284031215614f9a575f80fd5b5035919050565b80356001600160a01b0381168114614005575f80fd5b5f60208284031215614fc7575f80fd5b614f8382614fa1565b5f8083601f840112614fe0575f80fd5b50813567ffffffffffffffff811115614ff7575f80fd5b60208301915083602082850101111561500e575f80fd5b9250929050565b5f805f60408486031215615027575f80fd5b833567ffffffffffffffff81111561503d575f80fd5b61504986828701614fd0565b909790965060209590950135949350505050565b5f806020838503121561506e575f80fd5b823567ffffffffffffffff811115615084575f80fd5b61509085828601614fd0565b90969095509350505050565b5f60e08284031215613f58575f80fd5b5f805f805f606086880312156150c0575f80fd5b853567ffffffffffffffff808211156150d7575f80fd5b6150e389838a0161509c565b965060208801359150808211156150f8575f80fd5b61510489838a01614fd0565b9096509450604088013591508082111561511c575f80fd5b5061512988828901614fd0565b969995985093965092949392505050565b5f6020828403121561514a575f80fd5b813567ffffffffffffffff811115615160575f80fd5b61516c8482850161509c565b949350505050565b5f805f805f8060c08789031215615189575f80fd5b61519287614fa1565b95506151a060208801614fa1565b94506151ae60408801614fa1565b9350606087013592506080870135915060a087013590509295509295509295565b5f80604083850312156151e0575f80fd5b6151e983614fa1565b946020939093013593505050565b5f805f806040858703121561520a575f80fd5b843567ffffffffffffffff80821115615221575f80fd5b61522d88838901614fd0565b90965094506020870135915080821115615245575f80fd5b5061525287828801614fd0565b95989497509550505050565b80151581146132e3575f80fd5b5f6020828403121561527b575f80fd5b8135614f838161525e565b803567ffffffffffffffff81168114614005575f80fd5b5f80604083850312156152ae575f80fd5b6151e983615286565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561189a5761189a6152b7565b8181038181111561189a5761189a6152b7565b5f6020828403121561531a575f80fd5b5051919050565b5f60208284031215615331575f80fd5b813561ffff81168114614f83575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615375575f80fd5b83018035915067ffffffffffffffff82111561538f575f80fd5b60200191503681900382131561500e575f80fd5b5f602082840312156153b3575f80fd5b813560ff81168114614f83575f80fd5b5f602082840312156153d3575f80fd5b8151614f838161525e565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361540e5761540e6152b7565b5060010190565b5f60208284031215615425575f80fd5b614f8382615286565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156154b05760208186018101518583015201615496565b505f920191825250919050565b808202811582820484141761189a5761189a6152b7565b5f82615507577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a", } // RollupABI is the input ABI used to generate the binding from. @@ -891,6 +891,37 @@ func (_Rollup *RollupCallerSession) LastFinalizedBatchIndex() (*big.Int, error) return _Rollup.Contract.LastFinalizedBatchIndex(&_Rollup.CallOpts) } +// LegacyCutoverBatchIndex is a free data retrieval call binding the contract method 0x163d9bee. +// +// Solidity: function legacyCutoverBatchIndex() view returns(uint256) +func (_Rollup *RollupCaller) LegacyCutoverBatchIndex(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Rollup.contract.Call(opts, &out, "legacyCutoverBatchIndex") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// LegacyCutoverBatchIndex is a free data retrieval call binding the contract method 0x163d9bee. +// +// Solidity: function legacyCutoverBatchIndex() view returns(uint256) +func (_Rollup *RollupSession) LegacyCutoverBatchIndex() (*big.Int, error) { + return _Rollup.Contract.LegacyCutoverBatchIndex(&_Rollup.CallOpts) +} + +// LegacyCutoverBatchIndex is a free data retrieval call binding the contract method 0x163d9bee. +// +// Solidity: function legacyCutoverBatchIndex() view returns(uint256) +func (_Rollup *RollupCallerSession) LegacyCutoverBatchIndex() (*big.Int, error) { + return _Rollup.Contract.LegacyCutoverBatchIndex(&_Rollup.CallOpts) +} + // MessageQueue is a free data retrieval call binding the contract method 0x3b70c18a. // // Solidity: function messageQueue() view returns(address) @@ -1513,25 +1544,25 @@ func (_Rollup *RollupTransactorSession) Initialize3(_rollupDelayPeriod *big.Int) return _Rollup.Contract.Initialize3(&_Rollup.TransactOpts, _rollupDelayPeriod) } -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// Initialize4 is a paid mutator transaction binding the contract method 0x843bc9a1. // -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupTransactor) Initialize4(opts *bind.TransactOpts, _newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.contract.Transact(opts, "initialize4", _newSubmitter) +// Solidity: function initialize4(address _newSubmitter, uint256 _expectedLegacyCutoverBatchIndex) returns() +func (_Rollup *RollupTransactor) Initialize4(opts *bind.TransactOpts, _newSubmitter common.Address, _expectedLegacyCutoverBatchIndex *big.Int) (*types.Transaction, error) { + return _Rollup.contract.Transact(opts, "initialize4", _newSubmitter, _expectedLegacyCutoverBatchIndex) } -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// Initialize4 is a paid mutator transaction binding the contract method 0x843bc9a1. // -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +// Solidity: function initialize4(address _newSubmitter, uint256 _expectedLegacyCutoverBatchIndex) returns() +func (_Rollup *RollupSession) Initialize4(_newSubmitter common.Address, _expectedLegacyCutoverBatchIndex *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter, _expectedLegacyCutoverBatchIndex) } -// Initialize4 is a paid mutator transaction binding the contract method 0xf8fa010f. +// Initialize4 is a paid mutator transaction binding the contract method 0x843bc9a1. // -// Solidity: function initialize4(address _newSubmitter) returns() -func (_Rollup *RollupTransactorSession) Initialize4(_newSubmitter common.Address) (*types.Transaction, error) { - return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter) +// Solidity: function initialize4(address _newSubmitter, uint256 _expectedLegacyCutoverBatchIndex) returns() +func (_Rollup *RollupTransactorSession) Initialize4(_newSubmitter common.Address, _expectedLegacyCutoverBatchIndex *big.Int) (*types.Transaction, error) { + return _Rollup.Contract.Initialize4(&_Rollup.TransactOpts, _newSubmitter, _expectedLegacyCutoverBatchIndex) } // ProveState is a paid mutator transaction binding the contract method 0xb3484425. @@ -3333,15 +3364,16 @@ func (it *RollupSubmitterContractUpdatedIterator) Close() error { // RollupSubmitterContractUpdated represents a SubmitterContractUpdated event raised by the Rollup contract. type RollupSubmitterContractUpdated struct { - OldAddr common.Address - NewAddr common.Address - Raw types.Log // Blockchain specific contextual infos + OldAddr common.Address + NewAddr common.Address + LegacyCutoverBatchIndex *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterSubmitterContractUpdated is a free log retrieval operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// FilterSubmitterContractUpdated is a free log retrieval operation binding the contract event 0xaf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935. // -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) -func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterOpts, oldAddr []common.Address, newAddr []common.Address) (*RollupSubmitterContractUpdatedIterator, error) { +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr, uint256 indexed legacyCutoverBatchIndex) +func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterOpts, oldAddr []common.Address, newAddr []common.Address, legacyCutoverBatchIndex []*big.Int) (*RollupSubmitterContractUpdatedIterator, error) { var oldAddrRule []interface{} for _, oldAddrItem := range oldAddr { @@ -3351,18 +3383,22 @@ func (_Rollup *RollupFilterer) FilterSubmitterContractUpdated(opts *bind.FilterO for _, newAddrItem := range newAddr { newAddrRule = append(newAddrRule, newAddrItem) } + var legacyCutoverBatchIndexRule []interface{} + for _, legacyCutoverBatchIndexItem := range legacyCutoverBatchIndex { + legacyCutoverBatchIndexRule = append(legacyCutoverBatchIndexRule, legacyCutoverBatchIndexItem) + } - logs, sub, err := _Rollup.contract.FilterLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + logs, sub, err := _Rollup.contract.FilterLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule, legacyCutoverBatchIndexRule) if err != nil { return nil, err } return &RollupSubmitterContractUpdatedIterator{contract: _Rollup.contract, event: "SubmitterContractUpdated", logs: logs, sub: sub}, nil } -// WatchSubmitterContractUpdated is a free log subscription operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// WatchSubmitterContractUpdated is a free log subscription operation binding the contract event 0xaf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935. // -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) -func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpts, sink chan<- *RollupSubmitterContractUpdated, oldAddr []common.Address, newAddr []common.Address) (event.Subscription, error) { +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr, uint256 indexed legacyCutoverBatchIndex) +func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpts, sink chan<- *RollupSubmitterContractUpdated, oldAddr []common.Address, newAddr []common.Address, legacyCutoverBatchIndex []*big.Int) (event.Subscription, error) { var oldAddrRule []interface{} for _, oldAddrItem := range oldAddr { @@ -3372,8 +3408,12 @@ func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpt for _, newAddrItem := range newAddr { newAddrRule = append(newAddrRule, newAddrItem) } + var legacyCutoverBatchIndexRule []interface{} + for _, legacyCutoverBatchIndexItem := range legacyCutoverBatchIndex { + legacyCutoverBatchIndexRule = append(legacyCutoverBatchIndexRule, legacyCutoverBatchIndexItem) + } - logs, sub, err := _Rollup.contract.WatchLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule) + logs, sub, err := _Rollup.contract.WatchLogs(opts, "SubmitterContractUpdated", oldAddrRule, newAddrRule, legacyCutoverBatchIndexRule) if err != nil { return nil, err } @@ -3405,9 +3445,9 @@ func (_Rollup *RollupFilterer) WatchSubmitterContractUpdated(opts *bind.WatchOpt }), nil } -// ParseSubmitterContractUpdated is a log parse operation binding the contract event 0xde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939. +// ParseSubmitterContractUpdated is a log parse operation binding the contract event 0xaf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935. // -// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr) +// Solidity: event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr, uint256 indexed legacyCutoverBatchIndex) func (_Rollup *RollupFilterer) ParseSubmitterContractUpdated(log types.Log) (*RollupSubmitterContractUpdated, error) { event := new(RollupSubmitterContractUpdated) if err := _Rollup.contract.UnpackLog(event, "SubmitterContractUpdated", log); err != nil { diff --git a/bindings/bindings/rollup_more.go b/bindings/bindings/rollup_more.go index 46a077421..22ca0dd02 100644 --- a/bindings/bindings/rollup_more.go +++ b/bindings/bindings/rollup_more.go @@ -9,11 +9,11 @@ import ( "morph-l2/bindings/solc" ) -const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1030_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"submitterContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1030_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1032_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1032_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1033_storage\"},\"t_struct(BatchChallenge)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" +const RollupStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initialized\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint8\"},{\"astId\":1001,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_initializing\",\"offset\":1,\"slot\":\"0\",\"type\":\"t_bool\"},{\"astId\":1002,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_array(t_uint256)1032_storage\"},{\"astId\":1003,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_owner\",\"offset\":0,\"slot\":\"51\",\"type\":\"t_address\"},{\"astId\":1004,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"52\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1005,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"_paused\",\"offset\":0,\"slot\":\"101\",\"type\":\"t_bool\"},{\"astId\":1006,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__gap\",\"offset\":0,\"slot\":\"102\",\"type\":\"t_array(t_uint256)1031_storage\"},{\"astId\":1007,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"submitterContract\",\"offset\":0,\"slot\":\"151\",\"type\":\"t_address\"},{\"astId\":1008,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizationPeriodSeconds\",\"offset\":0,\"slot\":\"152\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofWindow\",\"offset\":0,\"slot\":\"153\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"__maxNumTxInChunk\",\"offset\":0,\"slot\":\"154\",\"type\":\"t_uint256\"},{\"astId\":1011,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"messageQueue\",\"offset\":0,\"slot\":\"155\",\"type\":\"t_address\"},{\"astId\":1012,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"verifier\",\"offset\":0,\"slot\":\"156\",\"type\":\"t_address\"},{\"astId\":1013,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastFinalizedBatchIndex\",\"offset\":0,\"slot\":\"157\",\"type\":\"t_uint256\"},{\"astId\":1014,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"lastCommittedBatchIndex\",\"offset\":0,\"slot\":\"158\",\"type\":\"t_uint256\"},{\"astId\":1015,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"isChallenger\",\"offset\":0,\"slot\":\"159\",\"type\":\"t_mapping(t_address,t_bool)\"},{\"astId\":1016,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"finalizedStateRoots\",\"offset\":0,\"slot\":\"160\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1017,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedBatches\",\"offset\":0,\"slot\":\"161\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1018,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchDataStore\",\"offset\":0,\"slot\":\"162\",\"type\":\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\"},{\"astId\":1019,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"withdrawalRoots\",\"offset\":0,\"slot\":\"163\",\"type\":\"t_mapping(t_bytes32,t_bool)\"},{\"astId\":1020,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"challenges\",\"offset\":0,\"slot\":\"164\",\"type\":\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\"},{\"astId\":1021,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallengeReward\",\"offset\":0,\"slot\":\"165\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1022,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"inChallenge\",\"offset\":0,\"slot\":\"166\",\"type\":\"t_bool\"},{\"astId\":1023,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchChallenged\",\"offset\":0,\"slot\":\"167\",\"type\":\"t_uint256\"},{\"astId\":1024,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"revertReqIndex\",\"offset\":0,\"slot\":\"168\",\"type\":\"t_uint256\"},{\"astId\":1025,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proofRewardPercent\",\"offset\":0,\"slot\":\"169\",\"type\":\"t_uint256\"},{\"astId\":1026,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"proveRemaining\",\"offset\":0,\"slot\":\"170\",\"type\":\"t_uint256\"},{\"astId\":1027,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"committedStateRoots\",\"offset\":0,\"slot\":\"171\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1028,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"rollupDelayPeriod\",\"offset\":0,\"slot\":\"172\",\"type\":\"t_uint256\"},{\"astId\":1029,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"batchBlobVersionedHashes\",\"offset\":0,\"slot\":\"173\",\"type\":\"t_mapping(t_uint256,t_bytes32)\"},{\"astId\":1030,\"contract\":\"contracts/l1/rollup/Rollup.sol:Rollup\",\"label\":\"legacyCutoverBatchIndex\",\"offset\":0,\"slot\":\"174\",\"type\":\"t_uint256\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_array(t_uint256)1031_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[49]\",\"numberOfBytes\":\"1568\"},\"t_array(t_uint256)1032_storage\":{\"encoding\":\"inplace\",\"label\":\"uint256[50]\",\"numberOfBytes\":\"1600\"},\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_address,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_bool\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_mapping(t_bytes32,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_mapping(t_uint256,t_struct(BatchChallenge)1033_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchChallenge)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchChallenge)1033_storage\"},\"t_mapping(t_uint256,t_struct(BatchData)1034_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct IRollup.BatchData)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BatchData)1034_storage\"},\"t_struct(BatchChallenge)1033_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchChallenge\",\"numberOfBytes\":\"128\"},\"t_struct(BatchData)1034_storage\":{\"encoding\":\"inplace\",\"label\":\"struct IRollup.BatchData\",\"numberOfBytes\":\"128\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"},\"t_uint8\":{\"encoding\":\"inplace\",\"label\":\"uint8\",\"numberOfBytes\":\"1\"}}}" var RollupStorageLayout = new(solc.StorageLayout) -var RollupDeployedBin = "0x60806040526004361061035e575f3560e01c806388b1ea09116101bd578063b8d0a1b0116100f2578063d8dc99d211610092578063e3fff1dd1161006d578063e3fff1dd14610b6b578063f2fde38b14610b8a578063f8fa010f14610ba9578063fb1e8b0414610bc8575f80fd5b8063d8dc99d214610b22578063de8b303514610b37578063dff7827e14610b56575f80fd5b8063cd4edc69116100cd578063cd4edc6914610abc578063ce5db8d614610acf578063cf9a674514610ae4578063d279c19114610b03575f80fd5b8063b8d0a1b014610a5f578063bedb86fb14610a7e578063c555389214610a9d575f80fd5b8063a479265d1161015d578063b31a77d311610138578063b31a77d3146109ed578063b348442514610a02578063b35dac4e14610a21578063b3e0a50914610a40575f80fd5b8063a479265d1461098e578063a4f209b0146109a3578063abc8d68d146109c2575f80fd5b8063910129d411610198578063910129d4146108e457806397fc007c14610915578063a3c9e94c14610934578063a415d8dc14610960575f80fd5b806388b1ea09146107d75780638da5cb5b146107f05780638f1d37761461081a575f80fd5b80632b7ac3f3116102935780635f77cf1d1161023357806368589dfa1161020e57806368589dfa1461075a5780636c578c1d14610785578063715018a6146107a4578063728cdbca146107b8575f80fd5b80635f77cf1d146106d0578063612672901461071c57806367caa37a1461073b575f80fd5b806341f756da1161026e57806341f756da146105fb57806357e0af6c1461060e5780635c975abb1461062d5780635ef7a94a14610644575f80fd5b80632b7ac3f3146105695780633b70c18a146105ba5780633e001b66146105e6575f80fd5b80631544ba3a116102fe57806321e2f9e0116102d957806321e2f9e0146104c95780632362f03e146104e85780632571098d146105135780632a213ba11461053e575f80fd5b80631544ba3a1461046557806318463fb01461048457806318af3b2b14610499575f80fd5b806310d445831161033957806310d44583146103f0578063116a1f421461040f578063121dcd50146104315780631336110114610446575f80fd5b806304d7721514610369578063059def61146103ac5780630ceb6780146103cf575f80fd5b3661036557005b5f80fd5b348015610374575f80fd5b50610397610383366004615e36565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b7575f80fd5b506103c1609d5481565b6040519081526020016103a3565b3480156103da575f80fd5b506103ee6103e9366004615e70565b610bdd565b005b3480156103fb575f80fd5b506103ee61040a366004615ece565b610d01565b34801561041a575f80fd5b50610397610429366004615e36565b609d54101590565b34801561043c575f80fd5b506103c1609e5481565b348015610451575f80fd5b506103ee610460366004615f16565b6110ed565b348015610470575f80fd5b506103ee61047f366004615f65565b61172f565b34801561048f575f80fd5b506103c160a75481565b3480156104a4575f80fd5b506103976104b3366004615e36565b5f90815260a26020526040902060010154421090565b3480156104d4575f80fd5b506103976104e3366004615e36565b611ba4565b3480156104f3575f80fd5b506103c1610502366004615e36565b60a16020525f908152604090205481565b34801561051e575f80fd5b506103c161052d366004615e36565b60a06020525f908152604090205481565b348015610549575f80fd5b506103c1610558366004615e36565b60ad6020525f908152604090205481565b348015610574575f80fd5b50609c546105959073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a3565b3480156105c5575f80fd5b50609b546105959073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105f1575f80fd5b506103c160aa5481565b6103ee610609366004615ff3565b611bd2565b348015610619575f80fd5b506103ee610628366004615e36565b611f65565b348015610638575f80fd5b5060655460ff16610397565b34801561064f575f80fd5b5061069a61065e366004615e36565b60a26020525f908152604090208054600182015460028301546003909301549192909173ffffffffffffffffffffffffffffffffffffffff1684565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080016103a3565b3480156106db575f80fd5b506107037f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103a3565b348015610727575f80fd5b506103ee610736366004615e36565b61202a565b348015610746575f80fd5b506103ee610755366004615ff3565b61228d565b348015610765575f80fd5b506103c1610774366004615e36565b60ab6020525f908152604090205481565b348015610790575f80fd5b506103ee61079f366004615e70565b612681565b3480156107af575f80fd5b506103ee612790565b3480156107c3575f80fd5b506103ee6107d236600461602d565b6127a3565b3480156107e2575f80fd5b5060a6546103979060ff1681565b3480156107fb575f80fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610595565b348015610825575f80fd5b50610893610834366004615e36565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff8316936801000000000000000090930473ffffffffffffffffffffffffffffffffffffffff16929060ff8082169161010090041686565b6040805167ffffffffffffffff909716875273ffffffffffffffffffffffffffffffffffffffff909516602087015293850192909252606084015215156080830152151560a082015260c0016103a3565b3480156108ef575f80fd5b506103976108fe366004615e36565b5f90815260a4602052604090206003015460ff1690565b348015610920575f80fd5b506103ee61092f366004615e70565b612b6c565b34801561093f575f80fd5b506097546105959073ffffffffffffffffffffffffffffffffffffffff1681565b34801561096b575f80fd5b5061039761097a366004615e70565b609f6020525f908152604090205460ff1681565b348015610999575f80fd5b506103c160995481565b3480156109ae575f80fd5b506103ee6109bd366004615e36565b612c90565b3480156109cd575f80fd5b506103c16109dc366004615e70565b60a56020525f908152604090205481565b3480156109f8575f80fd5b506103c160a85481565b348015610a0d575f80fd5b506103ee610a1c366004616088565b612d5a565b348015610a2c575f80fd5b506103ee610a3b366004615e70565b61314f565b348015610a4b575f80fd5b506103ee610a5a366004615f16565b6131b5565b348015610a6a575f80fd5b506103ee610a79366004616088565b6135ef565b348015610a89575f80fd5b506103ee610a983660046160fc565b613692565b348015610aa8575f80fd5b506103ee610ab7366004615e36565b613825565b6103ee610aca36600461612e565b6138e2565b348015610ada575f80fd5b506103c160985481565b348015610aef575f80fd5b506103ee610afe366004615e36565b613ff7565b348015610b0e575f80fd5b506103ee610b1d366004615e70565b6141d4565b348015610b2d575f80fd5b506103c160ac5481565b348015610b42575f80fd5b50610397610b51366004615e36565b6142ba565b348015610b61575f80fd5b506103c1609a5481565b348015610b76575f80fd5b506103ee610b85366004615e36565b614311565b348015610b95575f80fd5b506103ee610ba4366004615e70565b6143ce565b348015610bb4575f80fd5b506103ee610bc3366004615e70565b614482565b348015610bd3575f80fd5b506103c160a95481565b610be5614823565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff1615610c79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610d09614823565b5f8111610d72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610c70565b5f80610d7e85856148a4565b915091505f610d91836001015160c01c90565b5f81815260a160205260409020549091508214610e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b5f60a181610e188785616183565b81526020019081526020015f205414610eb2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610c70565b609d548111610f43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610c70565b610f4e600182616196565b609e555b83156110e557604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610f9a816142ba565b15611020575f81815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091610ff2908490616183565b909155505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b5f81815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a8541580159061109d575060a85481145b156110a7575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610f52575b505050505050565b60a85415611157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b61115f614966565b5f8061116b84846148a4565b915091505f61117e836001015160c01c90565b5f81815260a1602052604090205490915082146111f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b61120081611ba4565b611266576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c70565b61126f816142ba565b156112d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c70565b5f81815260a4602052604090206003015460ff1615611351576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610c70565b5f81815260a260205260409020600101544210156113cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610c70565b605983015160a05f6113de600185616196565b81526020019081526020015f205414611453576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c70565b5f81815260a06020526040902054156114c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610c70565b80609d5460010114611536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c70565b609d819055600160a35f61154b866099015190565b815260208101919091526040015f2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560798301515f82815260a060205260409020556115b86115ab846011015160c01c90565b600985015160c01c6149d3565b60a25f6115c6600184616196565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906116229084616196565b81526020019081526020015f205f905560ad5f6001836116429190616196565b81526020019081526020015f205f905560a45f6001836116629190616196565b815260208082019290925260409081015f90812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810182905560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61170b866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a85415611799576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b6117a1614966565b60ac54609e545f90815260a26020526040812054909142916117c39190616183565b1090505f4260ac54609b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611835573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061185991906161a9565b6118639190616183565b109050811580156118715750805b156118f2575f6118876080890160608a016161c0565b61ffff16116118f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b81806118fb5750805b611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610c70565b5f61197761197260208a018a6161e1565b6148a4565b5090505f611989826001015160c01c90565b611994906001616183565b5f81815260ad60205260408120549192509015611a4e575f4915611a3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610c70565b505f81815260ad6020526040902054611a69565b611a66611a5e60208c018c616242565b60ff16614a97565b90505b611a748a5f83614c06565b5f80611a808b8b6148a4565b915091505f611a93836001015160c01c90565b905080609e5414611b00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610c70565b5f81815260a160205260409020548214611b76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b5f81815260a26020526040902042600190910155611b95838b8b61521f565b50505050505050505050505050565b5f81815260a2602052604081205415801590611bcc57505f82815260a1602052604090205415155b92915050565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015611c58573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7c9190616262565b611ce2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b60a85415611d4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b611d54614966565b5f611d6561197260208401846161e1565b5090505f611d77826001015160c01c90565b611d82906001616183565b5f81815260ad602052604090205490915015611e20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610c70565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa158015611e91573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb591906161a9565b611ebf9190616183565b1015611f41575f611ed660808501606086016161c0565b61ffff1611611f41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b5f611f52611a5e6020860186616242565b9050611f5f843383614c06565b50505050565b611f6d614823565b5f81118015611f7e57506099548114155b611fe4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610c70565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff1615801561204a57505f5460ff8083169116105b6120d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff8316176101001790556121115f5460ff1690565b60ff1660021461217d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610c70565b8161220a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610c70565b609e545f90815260ab602052604090205461223357609e545f90815260ab602052604090208290555b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612313573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123379190616262565b61239d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b60a85415612407576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b61240f614966565b5f4915612478576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610c70565b5f61248961197260208401846161e1565b5090505f61249b826001015160c01c90565b6124a6906001616183565b5f81815260ad6020526040902054909150612543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610c70565b60ac54609b54604080517fb59b1a78000000000000000000000000000000000000000000000000000000008152905142939273ffffffffffffffffffffffffffffffffffffffff169163b59b1a789160048083019260209291908290030181865afa1580156125b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125d891906161a9565b6125e29190616183565b1015612664575f6125f960808501606086016161c0565b61ffff1611612664576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610c70565b61267c83335f84815260ad6020526040902054614c06565b505050565b612689614823565b73ffffffffffffffffffffffffffffffffffffffff81165f908152609f602052604090205460ff16612717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610c70565b73ffffffffffffffffffffffffffffffffffffffff81165f818152609f6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610cf6565b612798614823565b6127a15f6153f9565b565b5f54610100900460ff16158080156127c157505f54600160ff909116105b806127da5750303b1580156127da57505f5460ff166001145b612866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156128c2575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806128f9575073ffffffffffffffffffffffffffffffffffffffff8516155b15612930576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166129ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610c70565b6129b561546f565b6129bd61550d565b6097805473ffffffffffffffffffffffffffffffffffffffff808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612b63575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b612b74614823565b73ffffffffffffffffffffffffffffffffffffffff811615801590612bb45750609c5473ffffffffffffffffffffffffffffffffffffffff828116911614155b612c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610c70565b609c805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612c98614823565b5f81118015612ca8575060648111155b8015612cb6575060a9548114155b612d1c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610c70565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910161201e565b60a85415612dc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b612dcc614966565b60975473ffffffffffffffffffffffffffffffffffffffff16639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015612e52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190616262565b612edc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610c70565b5f80612ee886866148a4565b915091505f612efb836001015160c01c90565b5f81815260a160205260409020549091508214612f74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b612f7d816142ba565b612fe3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610c70565b5f81815260a4602052604090206003810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055609954600290910154429161305a91616183565b11613104575f81815260a460209081526040808320600390810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560a2835292819020909201548251808401909352600783527f54696d656f757400000000000000000000000000000000000000000000000000918301919091526130ff91839173ffffffffffffffffffffffffffffffffffffffff16906155ab565b612b63565b61310f83868661521f565b612b6381336040518060400160405280600d81526020017f50726f6f66207375636365737300000000000000000000000000000000000000815250615731565b613157614823565b60aa80545f9091556131698282615817565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d87910161201e565b6131bd614823565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea541561324e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610c70565b5f8061325a84846148a4565b915091505f61326d836001015160c01c90565b905080156132d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610c70565b5f6132e3846079015190565b90508061334c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610c70565b600984015160c01c156133bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610c70565b5f6133c7856019015190565b0361342e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610c70565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401461345a856039015190565b146134c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610c70565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f806135fb86866148a4565b915091505f61360e836001015160c01c90565b5f81815260a160205260409020549091508214613687576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b612b6383868661521f565b61369a614823565b80156137f3576136a86158e7565b60a65460ff16156137a55760a7545f90815260a4602090815260408083206001810154905468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16845260a59092528220805491929091613709908490616183565b909155505060a7545f90815260a46020526040812080547fffffffff0000000000000000000000000000000000000000000000000000000016815560018101829055600281019190915560030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b6137fb61596c565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336137c8565b50565b61382d614823565b5f8111801561383e575060ac548114155b6138a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610c70565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910161201e565b335f908152609f602052604090205460ff1661395a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610c70565b60a854156139c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b6139cc614966565b60a65460ff1615613a39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610c70565b8167ffffffffffffffff16609d5410613aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a160205260409020548114613b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610c70565b613b428267ffffffffffffffff16611ba4565b613ba8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a4602052604090205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615613c4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610c70565b67ffffffffffffffff82165f90815260a260205260409020600101544210613cf4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610c70565b60975f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d8291906161a9565b341015613deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610c70565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a49095529690962094518554925173ffffffffffffffffffffffffffffffffffffffff1668010000000000000000027fffffffff00000000000000000000000000000000000000000000000000000000909316981697909717178355945160018301559151600282015592516003909301805492511515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169290921792909217905573ffffffffffffffffffffffffffffffffffffffff168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b997634604051613f5791815260200190565b60405180910390a35f609d546001613f6f9190616183565b90505b609e548111613fc7578267ffffffffffffffff168114613fb5576099545f82815260a2602052604081206001018054909190613faf908490616183565b90915550505b80613fbf8161627d565b915050613f72565b505060a680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b5f54600390610100900460ff1615801561401757505f5460ff8083169116105b6140a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017815582900361413c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610c70565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b335f90815260a560205260408120549081900361424d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610c70565b335f90815260a560205260408120556142668282615817565b8173ffffffffffffffffffffffffffffffffffffffff167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a826040516142ae91815260200190565b60405180910390a25050565b5f81815260a4602052604081205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615801590611bcc5750505f90815260a46020526040902060030154610100900460ff161590565b614319614823565b5f8111801561432a57506098548114155b614390576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610c70565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910161201e565b6143d6614823565b73ffffffffffffffffffffffffffffffffffffffff8116614479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c70565b613822816153f9565b5f54600490610100900460ff161580156144a257505f5460ff8083169116105b61452e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610c70565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff83161761010017905573ffffffffffffffffffffffffffffffffffffffff82161580159061459957505f8273ffffffffffffffffffffffffffffffffffffffff163b115b6145ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610c70565b609d54609e541461466c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f70656e64696e67206261746368657300000000000000000000000000000000006044820152606401610c70565b60a65460ff16156146d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610c70565b60a85415614743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610c70565b60975460405173ffffffffffffffffffffffffffffffffffffffff8085169216907fde3ada76ae1aa387cc4c586c70304b9fae54b251958786c828aaa0ce0290f939905f90a3609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790555f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161201e565b60335473ffffffffffffffffffffffffffffffffffffffff1633146127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c70565b5f805f6148b185856159c3565b90505f8160ff165f036148d2576148c88686615a4d565b9094509050614958565b8160ff16600114806148e757508160ff166002145b156148f6576148c88686615ad0565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610c70565b808420925050509250929050565b60655460ff16156127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610c70565b805f036149de575050565b8082035f5b82811015611f5f576101008184038111156149fd57508083035b609b546040517f3c7f5283000000000000000000000000000000000000000000000000000000008152600481018590526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690633c7f5283906044015f604051808303815f87803b158015614a6d575f80fd5b505af1158015614a7f573d5f803e3d5ffd5b505050506101008301925050610100810190506149e3565b5f81600203614b40575f6040515f5b804980614ab35750614ac2565b60208202830152600101614aa6565b602081028083209201604052909250905080614b3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610c70565b50919050565b60014915614bd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610c70565b5f4915614bde575f49611bcc565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b6002614c156020850185616242565b60ff161115614c80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610c70565b6080830135614ceb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610c70565b60a0830135614d56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610c70565b5f80614d6861197260208701876161e1565b915091505f614d7b836001015160c01c90565b90505f60a181614d8c846001616183565b81526020019081526020015f205414614e01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610c70565b609e548114614e6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610c70565b5f81815260a160205260409020548214614ee2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610c70565b5f81815260ab6020526040902054608087013514614f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610c70565b5f614f6b846011015160c01c90565b90505f614f97614f8160608a0160408b016162b4565b614f9160808b0160608c016161c0565b84615b3d565b9050614fa96080890160608a016161c0565b60019384019361ffff91909116929092019160f990614fcb60208b018b616242565b60ff1610614fd857506101015b604080518281019091529550614ffd86614ff560208c018c616242565b60ff16615b81565b60c084901b600187015261502b8661501b60808c0160608d016161c0565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d98601859052600161507b60208b018b616242565b60ff16106150ad576150ad8661509760608c0160408d016162b4565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156151165760a7545f90815260a46020526040902060020154609954429161510991616183565b6151139190616196565b90505b604051806080016040528042815260200182609854426151369190616183565b6151409190616183565b815260200161515560608d0160408e016162b4565b67ffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b80615286576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610c70565b5f615295846001015160c01c90565b90505f6152a3856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006152d2876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c5490915073ffffffffffffffffffffffffffffffffffffffff16632c09a8486153a1885160f81c90565b858888866040518663ffffffff1660e01b81526004016153c59594939291906162cd565b5f6040518083038186803b1580156153db575f80fd5b505afa1580156153ed573d5f803e3d5ffd5b50505050505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff16615505576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1615b88565b5f54610100900460ff166155a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1615c48565b60a88390555f83815260a460205260408082205460975491517fc96be4cb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af115801561563f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061566391906161a9565b5f86815260a46020526040902060010154909150615682908290616183565b5f86815260a4602090815260408083205468010000000000000000900473ffffffffffffffffffffffffffffffffffffffff16835260a5909152812080549091906156ce908490616183565b90915550506040516156e1908490616330565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff84169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490615755908461635c565b61575f9190616373565b905061576b8183616196565b60aa5f82825461577b9190616183565b909155505073ffffffffffffffffffffffffffffffffffffffff84165f90815260a56020526040812080548392906157b4908490616183565b90915550506040516157c7908490616330565b6040519081900381209073ffffffffffffffffffffffffffffffffffffffff86169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b80156158e3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114615873576040519150601f19603f3d011682016040523d82523d5f602084013e615878565b606091505b505090508061267c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610c70565b5050565b6158ef614966565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586159423390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b615974615ce7565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33615942565b5f81615a2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610c70565b82825f818110615a3d57615a3d6163ab565b919091013560f81c949350505050565b5f8160f9811015615aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610c70565b6040519150808483378082016040529250929050565b5f816101018114615aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610c70565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101615b728161ffff871686615d53565b82900390912095945050505050565b8082535050565b5f54610100900460ff16615c1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b606580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b5f54610100900460ff16615cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610c70565b6127a1336153f9565b60655460ff166127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610c70565b5f825f03615d62575082615e2f565b609b5473ffffffffffffffffffffffffffffffffffffffff165f5b84811015615e29576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f9073ffffffffffffffffffffffffffffffffffffffff84169063ae453cd590602401602060405180830381865afa158015615df0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190615e1491906161a9565b87525060209095019460019384019301615d7d565b50849150505b9392505050565b5f60208284031215615e46575f80fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614c01575f80fd5b5f60208284031215615e80575f80fd5b615e2f82615e4d565b5f8083601f840112615e99575f80fd5b50813567ffffffffffffffff811115615eb0575f80fd5b602083019150836020828501011115615ec7575f80fd5b9250929050565b5f805f60408486031215615ee0575f80fd5b833567ffffffffffffffff811115615ef6575f80fd5b615f0286828701615e89565b909790965060209590950135949350505050565b5f8060208385031215615f27575f80fd5b823567ffffffffffffffff811115615f3d575f80fd5b615f4985828601615e89565b90969095509350505050565b5f60e08284031215614b3a575f80fd5b5f805f805f60608688031215615f79575f80fd5b853567ffffffffffffffff80821115615f90575f80fd5b615f9c89838a01615f55565b96506020880135915080821115615fb1575f80fd5b615fbd89838a01615e89565b90965094506040880135915080821115615fd5575f80fd5b50615fe288828901615e89565b969995985093965092949392505050565b5f60208284031215616003575f80fd5b813567ffffffffffffffff811115616019575f80fd5b61602584828501615f55565b949350505050565b5f805f805f8060c08789031215616042575f80fd5b61604b87615e4d565b955061605960208801615e4d565b945061606760408801615e4d565b9350606087013592506080870135915060a087013590509295509295509295565b5f805f806040858703121561609b575f80fd5b843567ffffffffffffffff808211156160b2575f80fd5b6160be88838901615e89565b909650945060208701359150808211156160d6575f80fd5b506160e387828801615e89565b95989497509550505050565b8015158114613822575f80fd5b5f6020828403121561610c575f80fd5b8135615e2f816160ef565b803567ffffffffffffffff81168114614c01575f80fd5b5f806040838503121561613f575f80fd5b61614883616117565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611bcc57611bcc616156565b81810381811115611bcc57611bcc616156565b5f602082840312156161b9575f80fd5b5051919050565b5f602082840312156161d0575f80fd5b813561ffff81168114615e2f575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112616214575f80fd5b83018035915067ffffffffffffffff82111561622e575f80fd5b602001915036819003821315615ec7575f80fd5b5f60208284031215616252575f80fd5b813560ff81168114615e2f575f80fd5b5f60208284031215616272575f80fd5b8151615e2f816160ef565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036162ad576162ad616156565b5060010190565b5f602082840312156162c4575f80fd5b615e2f82616117565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b8181101561634f5760208186018101518583015201616335565b505f920191825250919050565b8082028115828204841417611bcc57611bcc616156565b5f826163a6577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a" +var RollupDeployedBin = "0x608060405260043610610369575f3560e01c8063728cdbca116101c8578063b35dac4e116100fd578063cf9a67451161009d578063dff7827e1161006d578063dff7827e14610b20578063e3fff1dd14610b35578063f2fde38b14610b54578063fb1e8b0414610b73575f80fd5b8063cf9a674514610aae578063d279c19114610acd578063d8dc99d214610aec578063de8b303514610b01575f80fd5b8063bedb86fb116100d8578063bedb86fb14610a48578063c555389214610a67578063cd4edc6914610a86578063ce5db8d614610a99575f80fd5b8063b35dac4e146109eb578063b3e0a50914610a0a578063b8d0a1b014610a29575f80fd5b8063a3c9e94c11610168578063a4f209b011610143578063a4f209b01461096d578063abc8d68d1461098c578063b31a77d3146109b7578063b3484425146109cc575f80fd5b8063a3c9e94c1461090b578063a415d8dc1461092a578063a479265d14610958575f80fd5b80638da5cb5b116101a35780638da5cb5b146107ee5780638f1d37761461080b578063910129d4146108bb57806397fc007c146108ec575f80fd5b8063728cdbca14610797578063843bc9a1146107b657806388b1ea09146107d5575f80fd5b80632a213ba11161029e5780635ef7a94a1161023e57806367caa37a1161021957806367caa37a1461071a57806368589dfa146107395780636c578c1d14610764578063715018a614610783575f80fd5b80635ef7a94a1461063d5780635f77cf1d146106af57806361267290146106fb575f80fd5b80633e001b66116102795780633e001b66146105df57806341f756da146105f457806357e0af6c146106075780635c975abb14610626575f80fd5b80632a213ba11461055e5780632b7ac3f3146105895780633b70c18a146105c0575f80fd5b80631544ba3a1161030957806318af3b2b116102e457806318af3b2b146104b957806321e2f9e0146104e95780632362f03e146105085780632571098d14610533575f80fd5b80631544ba3a14610470578063163d9bee1461048f57806318463fb0146104a4575f80fd5b806310d445831161034457806310d44583146103fb578063116a1f421461041a578063121dcd501461043c5780631336110114610451575f80fd5b806304d7721514610374578063059def61146103b75780630ceb6780146103da575f80fd5b3661037057005b5f80fd5b34801561037f575f80fd5b506103a261038e366004614f8a565b60a36020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103c2575f80fd5b506103cc609d5481565b6040519081526020016103ae565b3480156103e5575f80fd5b506103f96103f4366004614fb7565b610b88565b005b348015610406575f80fd5b506103f9610415366004615015565b610c5a565b348015610425575f80fd5b506103a2610434366004614f8a565b609d54101590565b348015610447575f80fd5b506103cc609e5481565b34801561045c575f80fd5b506103f961046b36600461505d565b610f96565b34801561047b575f80fd5b506103f961048a3660046150ac565b6114b3565b34801561049a575f80fd5b506103cc60ae5481565b3480156104af575f80fd5b506103cc60a75481565b3480156104c4575f80fd5b506103a26104d3366004614f8a565b5f90815260a26020526040902060010154421090565b3480156104f4575f80fd5b506103a2610503366004614f8a565b611872565b348015610513575f80fd5b506103cc610522366004614f8a565b60a16020525f908152604090205481565b34801561053e575f80fd5b506103cc61054d366004614f8a565b60a06020525f908152604090205481565b348015610569575f80fd5b506103cc610578366004614f8a565b60ad6020525f908152604090205481565b348015610594575f80fd5b50609c546105a8906001600160a01b031681565b6040516001600160a01b0390911681526020016103ae565b3480156105cb575f80fd5b50609b546105a8906001600160a01b031681565b3480156105ea575f80fd5b506103cc60aa5481565b6103f961060236600461513a565b6118a0565b348015610612575f80fd5b506103f9610621366004614f8a565b611ba4565b348015610631575f80fd5b5060655460ff166103a2565b348015610648575f80fd5b50610686610657366004614f8a565b60a26020525f90815260409020805460018201546002830154600390930154919290916001600160a01b031684565b604080519485526020850193909352918301526001600160a01b031660608201526080016103ae565b3480156106ba575f80fd5b506106e27f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103ae565b348015610706575f80fd5b506103f9610715366004614f8a565b611c4f565b348015610725575f80fd5b506103f961073436600461513a565b611e2a565b348015610744575f80fd5b506103cc610753366004614f8a565b60ab6020525f908152604090205481565b34801561076f575f80fd5b506103f961077e366004614fb7565b612175565b34801561078e575f80fd5b506103f9612232565b3480156107a2575f80fd5b506103f96107b1366004615174565b612245565b3480156107c1575f80fd5b506103f96107d03660046151cf565b61254e565b3480156107e0575f80fd5b5060a6546103a29060ff1681565b3480156107f9575f80fd5b506033546001600160a01b03166105a8565b348015610816575f80fd5b50610877610825366004614f8a565b60a46020525f9081526040902080546001820154600283015460039093015467ffffffffffffffff831693680100000000000000009093046001600160a01b0316929060ff8082169161010090041686565b6040805167ffffffffffffffff90971687526001600160a01b03909516602087015293850192909252606084015215156080830152151560a082015260c0016103ae565b3480156108c6575f80fd5b506103a26108d5366004614f8a565b5f90815260a4602052604090206003015460ff1690565b3480156108f7575f80fd5b506103f9610906366004614fb7565b612895565b348015610916575f80fd5b506097546105a8906001600160a01b031681565b348015610935575f80fd5b506103a2610944366004614fb7565b609f6020525f908152604090205460ff1681565b348015610963575f80fd5b506103cc60995481565b348015610978575f80fd5b506103f9610987366004614f8a565b612978565b348015610997575f80fd5b506103cc6109a6366004614fb7565b60a56020525f908152604090205481565b3480156109c2575f80fd5b506103cc60a85481565b3480156109d7575f80fd5b506103f96109e63660046151f7565b612a28565b3480156109f6575f80fd5b506103f9610a05366004614fb7565b612d35565b348015610a15575f80fd5b506103f9610a2436600461505d565b612d8e565b348015610a34575f80fd5b506103f9610a433660046151f7565b61311f565b348015610a53575f80fd5b506103f9610a6236600461526b565b6131a8565b348015610a72575f80fd5b506103f9610a81366004614f8a565b6132e6565b6103f9610a9436600461529d565b613389565b348015610aa4575f80fd5b506103cc60985481565b348015610ab9575f80fd5b506103f9610ac8366004614f8a565b61391b565b348015610ad8575f80fd5b506103f9610ae7366004614fb7565b613a8a565b348015610af7575f80fd5b506103cc60ac5481565b348015610b0c575f80fd5b506103a2610b1b366004614f8a565b613b49565b348015610b2b575f80fd5b506103cc609a5481565b348015610b40575f80fd5b506103f9610b4f366004614f8a565b613b93565b348015610b5f575f80fd5b506103f9610b6e366004614fb7565b613c36565b348015610b7e575f80fd5b506103cc60a95481565b610b90613cc3565b6001600160a01b0381165f908152609f602052604090205460ff1615610bfd5760405162461bcd60e51b815260206004820152601f60248201527f6163636f756e7420697320616c72656164792061206368616c6c656e6765720060448201526064015b60405180910390fd5b6001600160a01b0381165f818152609f6020908152604091829020805460ff1916600190811790915591519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc00991015b60405180910390a250565b610c62613cc3565b5f8111610cb15760405162461bcd60e51b815260206004820152601560248201527f636f756e74206d757374206265206e6f6e7a65726f00000000000000000000006044820152606401610bf4565b5f80610cbd8585613d1d565b915091505f610cd0836001015160c01c90565b5f81815260a160205260409020549091508214610d2f5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f60a181610d3d87856152e4565b81526020019081526020015f205414610dbd5760405162461bcd60e51b8152602060048201526024808201527f726576657274696e67206d7573742073746172742066726f6d2074686520656e60448201527f64696e67000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b609d548111610e345760405162461bcd60e51b815260206004820152602160248201527f63616e206f6e6c792072657665727420756e46696e616c697a6564206261746360448201527f68000000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b610e3f6001826152f7565b609e555b8315610f8e57604051829082907ecae2739091badfd91c373f0a16cede691e0cd25bb80cff77dd5caeb4710146905f90a35f81815260a16020526040812055610e8b81613b49565b15610ee6575f81815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a59092528220805491929091610ed69084906152e4565b909155505060a6805460ff191690555b5f81815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a85415801590610f46575060a85481145b15610f50575f60a8555b6001015f81815260a160205260409020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193915081610e43575b505050505050565b60a85415610fe65760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b610fee613dc5565b5f80610ffa8484613d1d565b915091505f61100d836001015160c01c90565b5f81815260a16020526040902054909150821461106c5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b61107581611872565b6110c15760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b6110ca81613b49565b156111175760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a4602052604090206003015460ff16156111785760405162461bcd60e51b815260206004820152601660248201527f62617463682073686f756c6420626520726576657274000000000000000000006044820152606401610bf4565b5f81815260a260205260409020600101544210156111d85760405162461bcd60e51b815260206004820152601960248201527f626174636820696e206368616c6c656e67652077696e646f77000000000000006044820152606401610bf4565b605983015160a05f6111eb6001856152f7565b81526020019081526020015f2054146112465760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f81815260a06020526040902054156112a15760405162461bcd60e51b815260206004820152601660248201527f626174636820616c7265616479207665726966696564000000000000000000006044820152606401610bf4565b80609d54600101146112f55760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b609d819055600160a35f61130a866099015190565b815260208101919091526040015f20805460ff191691151591909117905560798301515f82815260a0602052604090205561135961134c846011015160c01c90565b600985015160c01c613e18565b60a25f6113676001846152f7565b815260208101919091526040015f908120818155600180820183905560028201839055600390910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560ab91906113c390846152f7565b81526020019081526020015f205f905560ad5f6001836113e391906152f7565b81526020019081526020015f205f905560a45f60018361140391906152f7565b815260208082019290925260409081015f90812080547fffffffff000000000000000000000000000000000000000000000000000000001681556001810182905560028101829055600301805461ffff1916905583815260a1909252902054817f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d61148f866079015190565b60998701516040805192835260208301919091520160405180910390a35050505050565b60a854156115035760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61150b613dc5565b60ac54609e545f90815260a260205260408120549091429161152d91906152e4565b1090505f4260ac54609b5f9054906101000a90046001600160a01b03166001600160a01b031663b59b1a786040518163ffffffff1660e01b8152600401602060405180830381865afa158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a9919061530a565b6115b391906152e4565b109050811580156115c15750805b15611628575f6115d76080890160608a01615321565b61ffff16116116285760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b81806116315750805b61167d5760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074696d696e670000000000000000000000000000000000006044820152606401610bf4565b5f61169361168e60208a018a615342565b613d1d565b5090505f6116a5826001015160c01c90565b6116b09060016152e4565b5f81815260ad60205260408120549192509015611750575f491561173c5760405162461bcd60e51b815260206004820152602f60248201527f6d757374206e6f7420636172727920626c6f62207768656e207573696e67207360448201527f746f72656420626c6f62206861736800000000000000000000000000000000006064820152608401610bf4565b505f81815260ad602052604090205461176b565b61176861176060208c018c6153a3565b60ff16613ecf565b90505b6117768a5f8361400a565b5f806117828b8b613d1d565b915091505f611795836001015160c01c90565b905080609e54146117e85760405162461bcd60e51b815260206004820152601660248201527f696e636f727265637420626174636820686561646572000000000000000000006044820152606401610bf4565b5f81815260a1602052604090205482146118445760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b5f81815260a26020526040902042600190910155611863838b8b614560565b50505050505050505050505050565b5f81815260a260205260408120541580159061189a57505f82815260a1602052604090205415155b92915050565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561190c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061193091906153c3565b61197c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a854156119cc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b6119d4613dc5565b5f6119e561168e6020840184615342565b5090505f6119f7826001015160c01c90565b611a029060016152e4565b5f81815260ad602052604090205490915015611a865760405162461bcd60e51b815260206004820152602860248201527f636f6d6d69744261746368207265717569726573206e6f2073746f726564206260448201527f6c6f6220686173680000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa158015611aea573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0e919061530a565b611b1891906152e4565b1015611b80575f611b2f6080850160608601615321565b61ffff1611611b805760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b5f611b9161176060208601866153a3565b9050611b9e84338361400a565b50505050565b611bac613cc3565b5f81118015611bbd57506099548114155b611c095760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964206e65772070726f6f662077696e646f7700000000000000006044820152606401610bf4565b609980549082905560408051828152602081018490527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a6191015b60405180910390a15050565b5f54600290610100900460ff16158015611c6f57505f5460ff8083169116105b611ce15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100179055611cff5f5460ff1690565b60ff16600214611d515760405162461bcd60e51b815260206004820152601660248201527f6d757374206861766520696e697469616c697a656421000000000000000000006044820152606401610bf4565b81611dc45760405162461bcd60e51b815260206004820152602760248201527f63616e206e6f742073657420737461746520726f6f742077697468206279746560448201527f73333228302921000000000000000000000000000000000000000000000000006064820152608401610bf4565b609e545f90815260ab6020526040902054611ded57609e545f90815260ab602052604090208290555b5f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611e96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eba91906153c3565b611f065760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b60a85415611f565760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b611f5e613dc5565b5f4915611fad5760405162461bcd60e51b815260206004820152601f60248201527f636f6d6d69745374617465206d757374206e6f7420636172727920626c6f62006044820152606401610bf4565b5f611fbe61168e6020840184615342565b5090505f611fd0826001015160c01c90565b611fdb9060016152e4565b5f81815260ad602052604090205490915061205e5760405162461bcd60e51b815260206004820152602260248201527f6e6f2073746f72656420626c6f62206861736820666f7220746869732062617460448201527f63680000000000000000000000000000000000000000000000000000000000006064820152608401610bf4565b60ac54609b54604080517fb59b1a7800000000000000000000000000000000000000000000000000000000815290514293926001600160a01b03169163b59b1a789160048083019260209291908290030181865afa1580156120c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120e6919061530a565b6120f091906152e4565b1015612158575f6121076080850160608601615321565b61ffff16116121585760405162461bcd60e51b815260206004820152600b60248201527f6c316d73672064656c61790000000000000000000000000000000000000000006044820152606401610bf4565b61217083335f84815260ad602052604090205461400a565b505050565b61217d613cc3565b6001600160a01b0381165f908152609f602052604090205460ff166121e45760405162461bcd60e51b815260206004820152601b60248201527f6163636f756e74206973206e6f742061206368616c6c656e67657200000000006044820152606401610bf4565b6001600160a01b0381165f818152609f60209081526040808320805460ff19169055519182527f7feb653c7b1f0d23daeed494225b3f28851cdc8973fcc653866d9b6e205fc0099101610c4f565b61223a613cc3565b6122435f614713565b565b5f54610100900460ff161580801561226357505f54600160ff909116105b8061227c5750303b15801561227c57505f5460ff166001145b6122ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805460ff19166001179055801561230f575f805461ff0019166101001790555b6001600160a01b038616158061232c57506001600160a01b038516155b15612363576040517fecc6fdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166123b95760405162461bcd60e51b815260206004820152601a60248201527f696e76616c6964207375626d697474657220636f6e74726163740000000000006044820152606401610bf4565b6123c161477c565b6123c9614800565b609780546001600160a01b03808a167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609b8054898416908316179055609c805492881692909116821790556098859055609984905560a98390556040515f907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96908290a3604080515f8152602081018690527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a437910160405180910390a1604080515f8152602081018590527f1e3a2094feb4b696dd3d7caea38ad2f41dbdcac3fa3943c7a693aff8a64b0a61910160405180910390a1604080515f8152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b0223910160405180910390a18015612545575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b5f54600490610100900460ff1615801561256e57505f5460ff8083169116105b6125e05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff83161761010017905561261b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b6001600160a01b0316336001600160a01b03161461267b5760405162461bcd60e51b815260206004820152601060248201527f6f6e6c792070726f78792061646d696e000000000000000000000000000000006044820152606401610bf4565b6001600160a01b0383161580159061269c57505f836001600160a01b03163b115b6126e85760405162461bcd60e51b815260206004820152601160248201527f696e76616c6964207375626d69747465720000000000000000000000000000006044820152606401610bf4565b81609e54146127395760405162461bcd60e51b815260206004820152601660248201527f6375746f766572206261746368206d69736d61746368000000000000000000006044820152606401610bf4565b60a65460ff161561278c5760405162461bcd60e51b815260206004820152601560248201527f6368616c6c656e676520696e2070726f677265737300000000000000000000006044820152606401610bf4565b60a854156127dc5760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b60ae82905560975460405183916001600160a01b03808716929116907faf9f8e4eb71b2fdd1ed3defb8e321359a8984ca774246d3d749837b98873a935905f90a4609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385161790555f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b61289d613cc3565b6001600160a01b038116158015906128c35750609c546001600160a01b03828116911614155b61290f5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206e65772076657269666965720000000000000000000000006044820152606401610bf4565b609c80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f728af3d16a5760405e27a082c98ab272e9f0a1d02f0085d41532a26093aedd96905f90a35050565b612980613cc3565b5f81118015612990575060648111155b801561299e575060a9548114155b6129ea5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c69642070726f6f66207265776172642070657263656e74616765006044820152606401610bf4565b60a980549082905560408051828152602081018490527ffb81bce17f015797e11949d3c332e2bf9453faf68f728447426803138f2b02239101611c43565b60a85415612a785760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b612a80613dc5565b6097546001600160a01b0316639f8a13d7336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015612aec573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b1091906153c3565b612b5c5760405162461bcd60e51b815260206004820152601d60248201527f6f6e6c7920616374697665207375626d697474657220616c6c6f7765640000006044820152606401610bf4565b5f80612b688686613d1d565b915091505f612b7b836001015160c01c90565b5f81815260a160205260409020549091508214612bda5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612be381613b49565b612c2f5760405162461bcd60e51b815260206004820152601260248201527f626174636820696e206368616c6c656e676500000000000000000000000000006044820152606401610bf4565b5f81815260a46020526040902060038101805461ff00191661010017905560a6805460ff191690556099546002909101544291612c6b916152e4565b11612cea575f81815260a4602090815260408083206003908101805460ff1916600117905560a2835292819020909201548251808401909352600783527f54696d656f75740000000000000000000000000000000000000000000000000091830191909152612ce59183916001600160a01b031690614884565b612545565b612cf5838686614560565b61254581336040518060400160405280600d81526020017f50726f6f662073756363657373000000000000000000000000000000000000008152506149e3565b612d3d613cc3565b60aa80545f909155612d4f8282614aaf565b604080516001600160a01b0384168152602081018390527fb1b2058a6969e2d25e47bcaebe8ae21c29a23b2752429315b75e2f4f285f3d879101611c43565b612d96613cc3565b5f805260a06020527fb84a74ec6ef4d0e83b6006dfaa014ab4026f9f3b97d186e604d29998a4e808ea5415612e0d5760405162461bcd60e51b815260206004820152601660248201527f67656e6573697320626174636820696d706f72746564000000000000000000006044820152606401610bf4565b5f80612e198484613d1d565b915091505f612e2c836001015160c01c90565b90508015612e7c5760405162461bcd60e51b815260206004820152601360248201527f696e76616c696420626174636820696e646578000000000000000000000000006044820152606401610bf4565b5f612e88846079015190565b905080612ed75760405162461bcd60e51b815260206004820152600f60248201527f7a65726f20737461746520726f6f7400000000000000000000000000000000006044820152606401610bf4565b600984015160c01c15612f2c5760405162461bcd60e51b815260206004820152601d60248201527f6c31206d65737361676520706f707065642073686f756c6420626520300000006044820152606401610bf4565b5f612f38856019015190565b03612f855760405162461bcd60e51b815260206004820152600e60248201527f7a65726f206461746120686173680000000000000000000000000000000000006044820152606401610bf4565b7f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014612fb1856039015190565b14612ffe5760405162461bcd60e51b815260206004820152601660248201527f696e76616c69642076657273696f6e65642068617368000000000000000000006044820152606401610bf4565b5f82815260a1602090815260408083208690558051608081018252428082528184019081528183018581526060830186815288875260a28652848720935184559151600184015551600283015551600390910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055603987015160ad83528184205560ab825280832084905560a0909152808220839055609e849055609d84905551849184917f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f9190a3604080518281525f6020820152849184917f26ba82f907317eedc97d0cbef23de76a43dd6edb563bdb6e9407645b950a7a2d910160405180910390a3505050505050565b5f8061312b8686613d1d565b915091505f61313e836001015160c01c90565b5f81815260a16020526040902054909150821461319d5760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b612545838686614560565b6131b0613cc3565b80156132b4576131be614b58565b60a65460ff16156132735760a7545f90815260a460209081526040808320600181015490546801000000000000000090046001600160a01b0316845260a590925282208054919290916132129084906152e4565b909155505060a7545f90815260a46020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181018290556002810191909155600301805461ffff1916905560a6805460ff191690555b7f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a150565b6132bc614bb2565b7f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33613296565b50565b6132ee613cc3565b5f811180156132ff575060ac548114155b61334b5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c6964206e657720726f6c6c75702064656c617920706572696f64006044820152606401610bf4565b60ac80549082905560408051828152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad19101611c43565b335f908152609f602052604090205460ff166133e75760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206368616c6c656e67657220616c6c6f7765640000000000000000006044820152606401610bf4565b60a854156134375760405162461bcd60e51b815260206004820152601660248201527f70656e64696e67207265766572742072657175657374000000000000000000006044820152606401610bf4565b61343f613dc5565b60a65460ff16156134925760405162461bcd60e51b815260206004820152601460248201527f616c726561647920696e206368616c6c656e67650000000000000000000000006044820152606401610bf4565b8167ffffffffffffffff16609d54106134ed5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c72656164792066696e616c697a65640000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a1602052604090205481146135545760405162461bcd60e51b815260206004820152601460248201527f696e636f727265637420626174636820686173680000000000000000000000006044820152606401610bf4565b6135678267ffffffffffffffff16611872565b6135b35760405162461bcd60e51b815260206004820152600f60248201527f6261746368206e6f7420657869737400000000000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a460205260409020546801000000000000000090046001600160a01b03161561362e5760405162461bcd60e51b815260206004820152601860248201527f626174636820616c7265616479206368616c6c656e67656400000000000000006044820152606401610bf4565b67ffffffffffffffff82165f90815260a2602052604090206001015442106136be5760405162461bcd60e51b815260206004820152603360248201527f63616e6e6f74206368616c6c656e6765206261746368206f757473696465207460448201527f6865206368616c6c656e67652077696e646f77000000000000000000000000006064820152608401610bf4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316630d13fd7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561370e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613732919061530a565b3410156137815760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742076616c756500000000000000000000000000006044820152606401610bf4565b67ffffffffffffffff82811660a78190556040805160c0810182528281523360208083018281523484860190815242606086019081525f6080870181815260a0880182815299825260a4909552969096209451855492516001600160a01b031668010000000000000000027fffffffff000000000000000000000000000000000000000000000000000000009093169816979097171783559451600183015591516002820155925160039093018054925115156101000261ff00199415159490941661ffff19909316929092179290921790556001600160a01b03168267ffffffffffffffff167f3a6ea19df25b49e7624e313ce7c1ab23984238e93727260db56a81735b1b99763460405161389991815260200190565b60405180910390a35f609d5460016138b191906152e4565b90505b609e548111613909578267ffffffffffffffff1681146138f7576099545f82815260a26020526040812060010180549091906138f19084906152e4565b90915550505b80613901816153de565b9150506138b4565b505060a6805460ff1916600117905550565b5f54600390610100900460ff1615801561393b57505f5460ff8083169116105b6139ad5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bf4565b5f805461ffff191660ff831617610100178155829003613a0f5760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420726f6c6c75702064656c617920706572696f6400000000006044820152606401610bf4565b60ac829055604080515f8152602081018490527f624e47dc9fb8f8cfeaf4ead4710277cc1757136cfa885e465514cf6d510f0ad1910160405180910390a15f805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c43565b335f90815260a5602052604081205490819003613ae95760405162461bcd60e51b815260206004820152601c60248201527f696e76616c69642062617463684368616c6c656e6765526577617264000000006044820152606401610bf4565b335f90815260a56020526040812055613b028282614aaf565b816001600160a01b03167f9c25fa83f414ed363c8d39c98fb3e17567b3431cede71eb062c49d2a63ce247a82604051613b3d91815260200190565b60405180910390a25050565b5f81815260a460205260408120546801000000000000000090046001600160a01b03161580159061189a5750505f90815260a46020526040902060030154610100900460ff161590565b613b9b613cc3565b5f81118015613bac57506098548114155b613bf85760405162461bcd60e51b815260206004820152601b60248201527f696e76616c6964206e65772066696e616c697a6520706572696f6400000000006044820152606401610bf4565b609880549082905560408051828152602081018490527fa577f4223f91f74e2dad65bbb8c30807587ae95d0d34288057bb3ec0d398a4379101611c43565b613c3e613cc3565b6001600160a01b038116613cba5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610bf4565b6132e381614713565b6033546001600160a01b031633146122435760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610bf4565b5f805f613d2a8585614beb565b90505f8160ff165f03613d4b57613d418686614c5b565b9094509050613db7565b8160ff1660011480613d6057508160ff166002145b15613d6f57613d418686614cc4565b60405162461bcd60e51b815260206004820152601960248201527f556e737570706f727465642062617463682076657273696f6e000000000000006044820152606401610bf4565b808420925050509250929050565b60655460ff16156122435760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610bf4565b805f03613e23575050565b8082035f5b82811015611b9e57610100818403811115613e4257508083035b609b546040517f3c7f528300000000000000000000000000000000000000000000000000000000815260048101859052602481018390526001600160a01b0390911690633c7f5283906044015f604051808303815f87803b158015613ea5575f80fd5b505af1158015613eb7573d5f803e3d5ffd5b50505050610100830192505061010081019050613e28565b5f81600203613f5e575f6040515f5b804980613eeb5750613efa565b60208202830152600101613ede565b602081028083209201604052909250905080613f585760405162461bcd60e51b815260206004820152601b60248201527f5632207265717569726573206174206c65617374203120626c6f6200000000006044820152606401610bf4565b50919050565b60014915613fd45760405162461bcd60e51b815260206004820152602560248201527f6c6567616379206261746368657320737570706f72742065786163746c79203160448201527f20626c6f620000000000000000000000000000000000000000000000000000006064820152608401610bf4565b5f4915613fe2575f4961189a565b507f010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440145b919050565b600261401960208501856153a3565b60ff16111561406a5760405162461bcd60e51b815260206004820152600f60248201527f696e76616c69642076657273696f6e00000000000000000000000000000000006044820152606401610bf4565b60808301356140bb5760405162461bcd60e51b815260206004820152601b60248201527f70726576696f757320737461746520726f6f74206973207a65726f00000000006044820152606401610bf4565b60a083013561410c5760405162461bcd60e51b815260206004820152601660248201527f6e657720737461746520726f6f74206973207a65726f000000000000000000006044820152606401610bf4565b5f8061411e61168e6020870187615342565b915091505f614131836001015160c01c90565b90505f60a1816141428460016152e4565b81526020019081526020015f20541461419d5760405162461bcd60e51b815260206004820152601760248201527f626174636820616c726561647920636f6d6d69747465640000000000000000006044820152606401610bf4565b609e5481146141ee5760405162461bcd60e51b815260206004820152601560248201527f696e636f727265637420626174636820696e64657800000000000000000000006044820152606401610bf4565b5f81815260a16020526040902054821461424a5760405162461bcd60e51b815260206004820152601b60248201527f696e636f727265637420706172656e74206261746368206861736800000000006044820152606401610bf4565b5f81815260ab60205260409020546080870135146142aa5760405162461bcd60e51b815260206004820152601d60248201527f696e636f72726563742070726576696f757320737461746520726f6f740000006044820152606401610bf4565b5f6142b9846011015160c01c90565b90505f6142e56142cf60608a0160408b01615415565b6142df60808b0160608c01615321565b84614d17565b90506142f76080890160608a01615321565b60019384019361ffff91909116929092019160f99061431960208b018b6153a3565b60ff161061432657506101015b60408051828101909152955061434b8661434360208c018c6153a3565b60ff16614d5b565b60c084901b60018701526143798661436960808c0160608d01615321565b61ffff1660c01b60099190910152565b60c083811b6011880152601987018390526039870188905260808a0135605988015260a08a0135607988015289013560998701525f60b987015260d9860185905260016143c960208b018b6153a3565b60ff16106143fb576143fb866143e560608c0160408d01615415565b67ffffffffffffffff1660c01b60f99190910152565b8086205f85815260a1602090815260408083209390935560ab815282822060a08d0135905560ad905290812088905560a65460ff16156144645760a7545f90815260a460205260409020600201546099544291614457916152e4565b61446191906152f7565b90505b6040518060800160405280428152602001826098544261448491906152e4565b61448e91906152e4565b81526020016144a360608d0160408e01615415565b67ffffffffffffffff1681526001600160a01b038b81166020928301525f88815260a28352604080822085518155858501516001820155858201516002820155606090950151600390950180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169590931694909417909155609e88905560a19091528181205491519193508692507f2c32d4ae151744d0bf0b9464a3e897a1d17ed2f1af71f7c9a75f12ce0d28238f91a35050505050505050565b806145ad5760405162461bcd60e51b815260206004820152601360248201527f496e76616c69642062617463682070726f6f66000000000000000000000000006044820152606401610bf4565b5f6145bc846001015160c01c90565b90505f6145ca856039015190565b90505f7f00000000000000000000000000000000000000000000000000000000000000006145f9876059015190565b6079880151609989015160b98a015160198b015160405160c09690961b7fffffffffffffffff000000000000000000000000000000000000000000000000166020870152602886019490945260488501929092526068840152608883015260a882015260c8810183905260e801604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120609c549091506001600160a01b0316632c09a8486146bb885160f81c90565b858888866040518663ffffffff1660e01b81526004016146df95949392919061542e565b5f6040518083038186803b1580156146f5575f80fd5b505afa158015614707573d5f803e3d5ffd5b50505050505050505050565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f54610100900460ff166147f85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614d62565b5f54610100900460ff1661487c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b612243614dea565b60a88390555f83815260a460205260408082205460975491517fc96be4cb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526801000000000000000090920482169392919091169063c96be4cb906024016020604051808303815f875af115801561490b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061492f919061530a565b5f86815260a4602052604090206001015490915061494e9082906152e4565b5f86815260a460209081526040808320546801000000000000000090046001600160a01b0316835260a59091528120805490919061498d9084906152e4565b90915550506040516149a0908490615491565b604051908190038120906001600160a01b0384169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b5f83815260a4602052604081206001015460a954909190606490614a0790846154bd565b614a1191906154d4565b9050614a1d81836152f7565b60aa5f828254614a2d91906152e4565b90915550506001600160a01b0384165f90815260a5602052604081208054839290614a599084906152e4565b9091555050604051614a6c908490615491565b604051908190038120906001600160a01b0386169087907fe70d3820e244d5f71d1a6395db24f3460e8dca966edc1fd3625b6292880a877a905f90a45050505050565b8015614b54575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614afe576040519150601f19603f3d011682016040523d82523d5f602084013e614b03565b606091505b50509050806121705760405162461bcd60e51b815260206004820152601b60248201527f526f6c6c75703a20455448207472616e73666572206661696c656400000000006044820152606401610bf4565b5050565b614b60613dc5565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614b953390565b6040516001600160a01b03909116815260200160405180910390a1565b614bba614e6f565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33614b95565b5f81614c395760405162461bcd60e51b815260206004820152601260248201527f456d7074792062617463682068656164657200000000000000000000000000006044820152606401610bf4565b82825f818110614c4b57614c4b61550c565b919091013560f81c949350505050565b5f8160f9811015614cae5760405162461bcd60e51b815260206004820152601d60248201527f626174636820686561646572206c656e67746820746f6f20736d616c6c0000006044820152606401610bf4565b6040519150808483378082016040529250929050565b5f816101018114614cae5760405162461bcd60e51b815260206004820181905260248201527f626174636820686561646572206c656e67746820697320696e636f72726563746044820152606401610bf4565b6040805160c085901b815260f084901b6008820152600a60208502820181019092525f918101614d4c8161ffff871686614ec1565b82900390912095945050505050565b8082535050565b5f54610100900460ff16614dde5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b6065805460ff19169055565b5f54610100900460ff16614e665760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bf4565b61224333614713565b60655460ff166122435760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610bf4565b5f825f03614ed0575082614f83565b609b546001600160a01b03165f5b84811015614f7d576040517fae453cd5000000000000000000000000000000000000000000000000000000008152600481018590525f906001600160a01b0384169063ae453cd590602401602060405180830381865afa158015614f44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614f68919061530a565b87525060209095019460019384019301614ede565b50849150505b9392505050565b5f60208284031215614f9a575f80fd5b5035919050565b80356001600160a01b0381168114614005575f80fd5b5f60208284031215614fc7575f80fd5b614f8382614fa1565b5f8083601f840112614fe0575f80fd5b50813567ffffffffffffffff811115614ff7575f80fd5b60208301915083602082850101111561500e575f80fd5b9250929050565b5f805f60408486031215615027575f80fd5b833567ffffffffffffffff81111561503d575f80fd5b61504986828701614fd0565b909790965060209590950135949350505050565b5f806020838503121561506e575f80fd5b823567ffffffffffffffff811115615084575f80fd5b61509085828601614fd0565b90969095509350505050565b5f60e08284031215613f58575f80fd5b5f805f805f606086880312156150c0575f80fd5b853567ffffffffffffffff808211156150d7575f80fd5b6150e389838a0161509c565b965060208801359150808211156150f8575f80fd5b61510489838a01614fd0565b9096509450604088013591508082111561511c575f80fd5b5061512988828901614fd0565b969995985093965092949392505050565b5f6020828403121561514a575f80fd5b813567ffffffffffffffff811115615160575f80fd5b61516c8482850161509c565b949350505050565b5f805f805f8060c08789031215615189575f80fd5b61519287614fa1565b95506151a060208801614fa1565b94506151ae60408801614fa1565b9350606087013592506080870135915060a087013590509295509295509295565b5f80604083850312156151e0575f80fd5b6151e983614fa1565b946020939093013593505050565b5f805f806040858703121561520a575f80fd5b843567ffffffffffffffff80821115615221575f80fd5b61522d88838901614fd0565b90965094506020870135915080821115615245575f80fd5b5061525287828801614fd0565b95989497509550505050565b80151581146132e3575f80fd5b5f6020828403121561527b575f80fd5b8135614f838161525e565b803567ffffffffffffffff81168114614005575f80fd5b5f80604083850312156152ae575f80fd5b6151e983615286565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561189a5761189a6152b7565b8181038181111561189a5761189a6152b7565b5f6020828403121561531a575f80fd5b5051919050565b5f60208284031215615331575f80fd5b813561ffff81168114614f83575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615375575f80fd5b83018035915067ffffffffffffffff82111561538f575f80fd5b60200191503681900382131561500e575f80fd5b5f602082840312156153b3575f80fd5b813560ff81168114614f83575f80fd5b5f602082840312156153d3575f80fd5b8151614f838161525e565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361540e5761540e6152b7565b5060010190565b5f60208284031215615425575f80fd5b614f8382615286565b85815284602082015260806040820152826080820152828460a08301375f60a084830101525f60a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b5f82515f5b818110156154b05760208186018101518583015201615496565b505f920191825250919050565b808202811582820484141761189a5761189a6152b7565b5f82615507577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea164736f6c6343000818000a" func init() { if err := json.Unmarshal([]byte(RollupStorageLayoutJSON), RollupStorageLayout); err != nil { diff --git a/common/batch/batch_cache.go b/common/batch/batch_cache.go index 933d678dc..fd17727ff 100644 --- a/common/batch/batch_cache.go +++ b/common/batch/batch_cache.go @@ -89,6 +89,18 @@ const batchProgressLogStepPercent uint64 = 20 // batches already committed on L1 (independent of max_blob_count flag). const replayProtocolMaxBlobs = 6 +// ErrLegacyTransitionCacheRequired means the Rollup still has pre-upgrade, +// unfinalized batches and therefore cannot be recovered with the post-upgrade +// zero-sequencer-field replay algorithm. The canonical sealed-batch window must +// be migrated intact and startup must fail closed if it is unavailable. +var ErrLegacyTransitionCacheRequired = errors.New("canonical legacy transition cache required") + +// ErrBatchCacheNotInitialized prevents callers from reading persisted or +// in-memory batches before startup validation has completed. In particular, a +// failed legacy transition validation must never leak an unvalidated batch to +// the commit path. +var ErrBatchCacheNotInitialized = errors.New("batch cache is not initialized") + // NewBatchCache creates and initializes a new BatchCache instance func NewBatchCache( isBatchUpgraded func(uint64) bool, @@ -156,6 +168,17 @@ func (bc *BatchCache) Init() error { if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } + cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) + if err != nil { + return err + } + if transition { + return legacyTransitionCacheError( + "cannot rebuild from finalized batch %d while legacy cutover batch %d is still pending", + fi.Uint64(), + cutover, + ) + } headerBytes, err := bc.getLastFinalizeBatchHeaderFromRollupByIndex(fi.Uint64()) if err != nil { return fmt.Errorf("get last finalize batch header err: %w", err) @@ -231,16 +254,40 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } + cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) + if err != nil { + return err + } batches, headers, indices, err := bc.batchStorage.LoadAllSealedBatchesAndHeader() if err != nil { - log.Error("Failed to load sealed batch headers from storage", "error", err) - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("load sealed batch headers: %w", err), + ) } if len(batches) == 0 { + if transition { + return legacyTransitionCacheError( + "empty sealed-batch storage for pending legacy window [%d,%d]", + fi.Uint64(), + cutover, + ) + } return bc.initAndSyncFromRollupLocked() } + if len(indices) == 0 { + return bc.handleInvalidStoredBatchCache( + transition, + errors.New("sealed batches exist without an indices snapshot"), + ) + } + if transition { + if err := validateLegacyTransitionWindow(batches, headers, indices, fi.Uint64(), ci.Uint64(), cutover); err != nil { + return legacyTransitionCacheError("invalid migrated cache: %v", err) + } + } maxIndex := indices[0] for _, idx := range indices { if idx > maxIndex { @@ -256,20 +303,27 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { batchStorage, exist := batches[i] if !exist || !bytes.Equal(batchHash[:], batchStorage.Hash.Bytes()) { // batch not contiguous or batch is invalid - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("batch %d missing or does not match committed hash", i), + ) } } latestHeaderBytes := headers[maxIndex] prevStateRoot, err := latestHeaderBytes.PostStateRoot() if err != nil { - log.Error("Get post state root failed", "err", err) - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("get latest cached post state root: %w", err), + ) } totalL1MessagePopped, err := latestHeaderBytes.TotalL1MessagePopped() if err != nil { - log.Error("Get total l1 message popped failed", "err", err) - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("get latest cached total l1 messages: %w", err), + ) } lastPackedBlockHeight, err := latestHeaderBytes.LastBlockNumber() if err != nil { @@ -281,17 +335,22 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { // check batch index range if latestBatchIndex < fi.Uint64() || latestBatchIndex > ci.Uint64() { // missing batch data, sync from another side - log.Error("Batch index is out of range", - "latestBatchIndex", latestBatchIndex, - "commitIndex", ci.Uint64(), "finalizeIndex", fi.Uint64()) - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf( + "latest cached batch index %d is outside rollup range [%d,%d]", + latestBatchIndex, + fi.Uint64(), + ci.Uint64(), + ), + ) } store, err := bc.rollupContract.BatchDataStore(nil, new(big.Int).SetUint64(latestBatchIndex)) if err != nil { - log.Error("Failed to load latest batch index from rollup", - "error", err, - "batchIndex", latestBatchIndex) - return bc.deleteBatchStorageAndInitFromRollupLocked() + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("load batch data for cached batch %d: %w", latestBatchIndex, err), + ) } lastPackedBlockHeight = store.BlockNumber.Uint64() } @@ -306,7 +365,12 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { bc.initDone = true bc.mu.Unlock() - log.Info("Sync sealed batch from database success", "count", len(batches)) + log.Info( + "Sync sealed batch from database success", + "count", len(batches), + "legacyTransition", transition, + "legacyCutoverBatchIndex", cutover, + ) return nil } @@ -398,6 +462,262 @@ func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { return latestCommitBatchIndex, lastFinalizedBatchIndex, nil } +func (bc *BatchCache) getLegacyTransitionStatus(ci, fi *big.Int) (uint64, bool, error) { + cutover, err := bc.rollupContract.LegacyCutoverBatchIndex(nil) + if err != nil { + return 0, false, fmt.Errorf("get legacy cutover batch index: %w", err) + } + if cutover == nil || cutover.Sign() < 0 { + return 0, false, errors.New("invalid legacy cutover batch index") + } + if cutover.Cmp(ci) > 0 { + return 0, false, fmt.Errorf( + "legacy cutover batch index %s is ahead of last committed batch %s", + cutover, + ci, + ) + } + return cutover.Uint64(), fi.Cmp(cutover) < 0, nil +} + +func legacyTransitionCacheError(format string, args ...interface{}) error { + return fmt.Errorf("%w: %s", ErrLegacyTransitionCacheRequired, fmt.Sprintf(format, args...)) +} + +func (bc *BatchCache) handleInvalidStoredBatchCache(transition bool, cause error) error { + if transition { + return legacyTransitionCacheError("%v", cause) + } + log.Error("Invalid sealed batch cache; rebuilding from rollup", "error", cause) + return bc.deleteBatchStorageAndInitFromRollupLocked() +} + +// validateLegacyTransitionWindow applies the additional invariants needed while +// a pre-upgrade batch remains unfinalized. LoadAllSealedBatchesAndHeader already +// checks the persisted parent chain and header hashes; this function makes sure +// the complete canonical on-chain window is present and prevents pre-upgrade, +// locally sealed batches beyond the cutover from becoming post-upgrade parents. +func validateLegacyTransitionWindow( + batches map[uint64]*eth.RPCRollupBatch, + headers map[uint64]*BatchHeaderBytes, + indices []uint64, + finalized uint64, + committed uint64, + cutover uint64, +) error { + if finalized >= cutover { + return fmt.Errorf("legacy transition is not active: finalized=%d cutover=%d", finalized, cutover) + } + if cutover > committed { + return fmt.Errorf("legacy cutover %d is ahead of committed batch %d", cutover, committed) + } + + for idx := finalized; ; idx++ { + batch := batches[idx] + if batch == nil { + return fmt.Errorf("canonical batch %d is missing", idx) + } + header := headers[idx] + if header == nil { + return fmt.Errorf("canonical batch header %d is missing", idx) + } + if err := validateLegacyTransitionRecord(idx, batch, header, false); err != nil { + return err + } + if idx == committed { + break + } + } + + if headers[cutover] == nil { + return fmt.Errorf("legacy cutover header %d is missing", cutover) + } + + for _, idx := range indices { + if idx <= cutover { + continue + } + batch := batches[idx] + if batch == nil { + return fmt.Errorf("post-cutover batch %d is missing", idx) + } + header := headers[idx] + if header == nil { + return fmt.Errorf("post-cutover batch header %d is missing", idx) + } + if err := validateLegacyTransitionRecord(idx, batch, header, idx > committed); err != nil { + return err + } + sequencerHash, err := header.SequencerSetVerifyHash() + if err != nil { + return fmt.Errorf("read batch %d sequencer-set hash: %w", idx, err) + } + if sequencerHash != (common.Hash{}) { + return fmt.Errorf( + "batch %d is beyond legacy cutover %d but has non-zero sequencer-set hash %s", + idx, + cutover, + sequencerHash, + ) + } + } + return nil +} + +func validateLegacyTransitionRecord( + index uint64, + batch *eth.RPCRollupBatch, + header *BatchHeaderBytes, + validateBroadcastFields bool, +) error { + headerIndex, err := header.BatchIndex() + if err != nil { + return fmt.Errorf("read batch header %d index: %w", index, err) + } + if headerIndex != index { + return fmt.Errorf("batch header key %d contains index %d", index, headerIndex) + } + + version, err := header.Version() + if err != nil { + return fmt.Errorf("read batch header %d version: %w", index, err) + } + if batch.Version != uint(version) { + return fmt.Errorf("batch %d version mismatch: record=%d header=%d", index, batch.Version, version) + } + + // Batch zero is the genesis header and has no preceding batch header. + if index > 0 { + parentHeader := BatchHeaderBytes(batch.ParentBatchHeader) + parentHash, err := parentHeader.Hash() + if err != nil { + return fmt.Errorf("hash batch %d parent header: %w", index, err) + } + headerParentHash, err := header.ParentBatchHash() + if err != nil { + return fmt.Errorf("read batch header %d parent hash: %w", index, err) + } + if headerParentHash != parentHash { + return fmt.Errorf( + "batch header %d parent hash mismatch: record=%s header=%s", + index, + parentHash, + headerParentHash, + ) + } + parentIndex, err := parentHeader.BatchIndex() + if err != nil { + return fmt.Errorf("read batch %d parent index: %w", index, err) + } + if parentIndex != index-1 { + return fmt.Errorf("batch %d parent header contains index %d", index, parentIndex) + } + } + + prevStateRoot, err := header.PrevStateRoot() + if err != nil { + return fmt.Errorf("read batch header %d previous state root: %w", index, err) + } + postStateRoot, err := header.PostStateRoot() + if err != nil { + return fmt.Errorf("read batch header %d post state root: %w", index, err) + } + withdrawalRoot, err := header.WithdrawalRoot() + if err != nil { + return fmt.Errorf("read batch header %d withdrawal root: %w", index, err) + } + if batch.PrevStateRoot != prevStateRoot || batch.PostStateRoot != postStateRoot || batch.WithdrawRoot != withdrawalRoot { + return fmt.Errorf("batch %d state roots do not match its header", index) + } + + if version >= BatchHeaderVersion1 { + lastBlock, err := header.LastBlockNumber() + if err != nil { + return fmt.Errorf("read batch header %d last block: %w", index, err) + } + if batch.LastBlockNumber != lastBlock { + return fmt.Errorf( + "batch %d last block mismatch: record=%d header=%d", + index, + batch.LastBlockNumber, + lastBlock, + ) + } + } + + // Committed historical records are authenticated by their on-chain header + // hash and may come from old databases that did not retain a complete + // sidecar. Only locally sealed records beyond currentCommitted can be + // broadcast in the future, so validate all calldata/blob-derived fields for + // those records before accepting them as a restart parent. + if validateBroadcastFields { + l1MessagePopped, err := header.L1MessagePopped() + if err != nil { + return fmt.Errorf("read batch header %d L1 message count: %w", index, err) + } + if uint64(batch.NumL1Messages) != l1MessagePopped { + return fmt.Errorf( + "batch %d L1 message count mismatch: record=%d header=%d", + index, + batch.NumL1Messages, + l1MessagePopped, + ) + } + + parentHeader := BatchHeaderBytes(batch.ParentBatchHeader) + parentTotal, err := parentHeader.TotalL1MessagePopped() + if err != nil { + return fmt.Errorf("read batch %d parent total L1 messages: %w", index, err) + } + total, err := header.TotalL1MessagePopped() + if err != nil { + return fmt.Errorf("read batch header %d total L1 messages: %w", index, err) + } + messageCount := uint64(batch.NumL1Messages) + if parentTotal > ^uint64(0)-messageCount || parentTotal+messageCount != total { + return fmt.Errorf( + "batch %d cumulative L1 message mismatch: parent=%d batch=%d header=%d", + index, + parentTotal, + messageCount, + total, + ) + } + + if len(batch.Sidecar.Blobs) == 0 || len(batch.Sidecar.Blobs) != len(batch.Sidecar.Commitments) { + return fmt.Errorf( + "batch %d invalid sidecar cardinality: blobs=%d commitments=%d", + index, + len(batch.Sidecar.Blobs), + len(batch.Sidecar.Commitments), + ) + } + blobHashes := blob.BlobHashes(batch.Sidecar.Blobs, batch.Sidecar.Commitments) + var sidecarCommitHash common.Hash + if version >= BatchHeaderVersion2 { + sidecarCommitHash = aggregateBlobHashes(blobHashes) + } else { + if len(blobHashes) != 1 { + return fmt.Errorf("batch %d header version %d requires exactly one blob, got %d", index, version, len(blobHashes)) + } + sidecarCommitHash = blobHashes[0] + } + headerCommitHash, err := header.BlobCommitHash() + if err != nil { + return fmt.Errorf("read batch header %d blob commitment: %w", index, err) + } + if sidecarCommitHash != headerCommitHash { + return fmt.Errorf( + "batch %d sidecar commitment mismatch: sidecar=%s header=%s", + index, + sidecarCommitHash, + headerCommitHash, + ) + } + } + return nil +} + func (bc *BatchCache) getBatchBlockRange(batchIndex *big.Int) (uint64, uint64, error) { preIndex := new(big.Int).Sub(batchIndex, big.NewInt(1)) preBatchStorage, err := bc.rollupContract.BatchDataStore(nil, preIndex) @@ -1234,6 +1554,9 @@ func (bc *BatchCache) SealBatchAndCheck(ci *big.Int) (common.Hash, bool, uint64, func (bc *BatchCache) Get(batchIndex uint64) (*eth.RPCRollupBatch, error) { bc.mu.RLock() defer bc.mu.RUnlock() + if !bc.initDone { + return nil, ErrBatchCacheNotInitialized + } batch, ok := bc.sealedBatches[batchIndex] var err error if !ok { @@ -1552,6 +1875,22 @@ func (bc *BatchCache) DeleteBatchStorageAndInitFromRollup() error { } func (bc *BatchCache) deleteBatchStorageAndInitFromRollupLocked() error { + ci, fi, err := bc.getBatchStatusFromContract() + if err != nil { + return fmt.Errorf("get batch status before sealed-batch wipe: %w", err) + } + cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) + if err != nil { + return err + } + if transition { + return legacyTransitionCacheError( + "refusing to wipe canonical cache while pending legacy window [%d,%d] must be preserved", + fi.Uint64(), + cutover, + ) + } + // should delete invalid batch data and batch header bytes if err := bc.batchStorage.DeleteAllSealedBatches(); err != nil { // DeleteAllSealedBatches relies on a parseable sealed_batch_indices to diff --git a/common/batch/batch_transition_test.go b/common/batch/batch_transition_test.go new file mode 100644 index 000000000..646286100 --- /dev/null +++ b/common/batch/batch_transition_test.go @@ -0,0 +1,434 @@ +package batch + +import ( + "bytes" + "context" + "encoding/binary" + "math/big" + "testing" + + "morph-l2/bindings/bindings" + "morph-l2/common/blob" + + "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/eth" + "github.com/stretchr/testify/require" +) + +const ( + transitionFinalized = uint64(10) + transitionCutover = uint64(12) +) + +type transitionRollupReader struct { + committed uint64 + finalized uint64 + cutover uint64 + committedHash map[uint64][32]byte + batchBlockByID map[uint64]uint64 +} + +func (r *transitionRollupReader) CommittedBatches(_ *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { + return r.committedHash[batchIndex.Uint64()], nil +} + +func (r *transitionRollupReader) LastCommittedBatchIndex(_ *bind.CallOpts) (*big.Int, error) { + return new(big.Int).SetUint64(r.committed), nil +} + +func (r *transitionRollupReader) LastFinalizedBatchIndex(_ *bind.CallOpts) (*big.Int, error) { + return new(big.Int).SetUint64(r.finalized), nil +} + +func (r *transitionRollupReader) LegacyCutoverBatchIndex(_ *bind.CallOpts) (*big.Int, error) { + return new(big.Int).SetUint64(r.cutover), nil +} + +func (r *transitionRollupReader) BatchDataStore(_ *bind.CallOpts, batchIndex *big.Int) (struct { + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address +}, error) { + return struct { + OriginTimestamp *big.Int + FinalizeTimestamp *big.Int + BlockNumber *big.Int + Submitter common.Address + }{ + OriginTimestamp: new(big.Int), + FinalizeTimestamp: new(big.Int), + BlockNumber: new(big.Int).SetUint64(r.batchBlockByID[batchIndex.Uint64()]), + }, nil +} + +func (r *transitionRollupReader) FilterFinalizeBatch( + _ *bind.FilterOpts, + _ []*big.Int, + _ [][32]byte, +) (*bindings.RollupFinalizeBatchIterator, error) { + return nil, nil +} + +func newTransitionBatchCache(kv SealedBatchKV, rollup RollupBatchReader) *BatchCache { + return &BatchCache{ + ctx: context.Background(), + batchStorage: NewBatchStorage(kv), + sealedBatches: make(map[uint64]*eth.RPCRollupBatch), + sealedBatchHeaders: make(map[uint64]*BatchHeaderBytes), + batchData: NewBatchData(), + isBatchUpgraded: func(uint64) bool { return true }, + isBatchV2Upgraded: func(uint64) bool { return false }, + rollupContract: rollup, + maxBlobCount: 1, + } +} + +func makeTransitionHeader( + index uint64, + parentHash common.Hash, + sequencerHash common.Hash, + blobCommitHash common.Hash, +) BatchHeaderBytes { + return BatchHeaderV1{ + BatchHeaderV0: BatchHeaderV0{ + BatchIndex: index, + L1MessagePopped: 1, + TotalL1MessagePopped: index + 100, + DataHash: common.BigToHash(new(big.Int).SetUint64(index*10 + 1)), + BlobVersionedHash: blobCommitHash, + PrevStateRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 3)), + PostStateRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 4)), + WithdrawalRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 5)), + SequencerSetVerifyHash: sequencerHash, + ParentBatchHash: parentHash, + }, + LastBlockNumber: index * 10, + }.Bytes() +} + +// storeTransitionWindow persists a canonical, contiguous [F,last] snapshot and +// configures the fake rollup's committed hashes through K. Indices above K model +// batches sealed locally but not yet committed at the upgrade boundary. +func storeTransitionWindow( + t *testing.T, + kv SealedBatchKV, + last uint64, + postCutoverSequencerHash common.Hash, +) (*transitionRollupReader, map[uint64]BatchHeaderBytes) { + t.Helper() + + rollup := &transitionRollupReader{ + committed: transitionCutover, + finalized: transitionFinalized, + cutover: transitionCutover, + committedHash: make(map[uint64][32]byte), + batchBlockByID: make(map[uint64]uint64), + } + storage := NewBatchStorage(kv) + headers := make(map[uint64]BatchHeaderBytes) + legacySequencerHash := common.HexToHash("0x123456") + parentHeader := makeTransitionHeader( + transitionFinalized-1, + common.Hash{}, + legacySequencerHash, + common.BigToHash(new(big.Int).SetUint64((transitionFinalized-1)*10+2)), + ) + parentHash, err := parentHeader.Hash() + require.NoError(t, err) + + for index := transitionFinalized; index <= last; index++ { + sequencerHash := legacySequencerHash + blobCommitHash := common.BigToHash(new(big.Int).SetUint64(index*10 + 2)) + var sidecar ethtypes.BlobTxSidecar + if index > transitionCutover { + sequencerHash = postCutoverSequencerHash + generatedSidecar, sidecarErr := blob.MakeBlobTxSidecar(nil, 1) + require.NoError(t, sidecarErr) + sidecar = *generatedSidecar + blobHashes := sidecar.BlobHashes() + require.Len(t, blobHashes, 1) + blobCommitHash = blobHashes[0] + } + header := makeTransitionHeader(index, parentHash, sequencerHash, blobCommitHash) + hash, hashErr := header.Hash() + require.NoError(t, hashErr) + batch := ð.RPCRollupBatch{ + Version: uint(BatchHeaderVersion1), + Hash: hash, + ParentBatchHeader: hexutil.Bytes(parentHeader), + PrevStateRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 3)), + PostStateRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 4)), + WithdrawRoot: common.BigToHash(new(big.Int).SetUint64(index*10 + 5)), + LastBlockNumber: index * 10, + NumL1Messages: 1, + Sidecar: sidecar, + } + require.NoError(t, storage.StoreSealedBatchAndHeader(index, batch, &header)) + headers[index] = header + if index <= transitionCutover { + rollup.committedHash[index] = [32]byte(hash) + } + rollup.batchBlockByID[index] = index * 10 + parentHeader = header + parentHash = hash + } + return rollup, headers +} + +func requireTransitionStoragePreserved(t *testing.T, kv SealedBatchKV, index uint64) { + t.Helper() + _, err := kv.GetBytes(encodeBatchKey(index)) + require.NoError(t, err) + _, err = kv.GetBytes([]byte(SealedBatchIndicesKey)) + require.NoError(t, err) +} + +func mutateStoredTransitionRecord( + t *testing.T, + kv SealedBatchKV, + index uint64, + mutate func(*eth.RPCRollupBatch, *BatchHeaderBytes), +) { + t.Helper() + storage := NewBatchStorage(kv) + storedBatch, err := storage.LoadSealedBatch(index) + require.NoError(t, err) + storedHeader, err := storage.LoadSealedBatchHeader(index) + require.NoError(t, err) + mutate(storedBatch, storedHeader) + storedBatch.Hash, err = storedHeader.Hash() + require.NoError(t, err) + require.NoError(t, storage.StoreSealedBatchAndHeader(index, storedBatch, storedHeader)) +} + +func TestInitAndSyncFromDatabaseLegacyTransitionUsesExactCutoverParent(t *testing.T) { + kv := openTestKV(t) + rollup, headers := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + cache := newTransitionBatchCache(kv, rollup) + + require.NoError(t, cache.InitAndSyncFromDatabase()) + require.True(t, cache.isInitialized()) + require.Equal(t, headers[transitionCutover].Bytes(), cache.parentBatchHeader.Bytes()) + for index := transitionFinalized; index <= transitionCutover; index++ { + _, exists := cache.GetSealedBatchHeader(index) + require.True(t, exists, "finalizer must retain canonical header %d", index) + } + cutoverSequencerHash, err := cache.parentBatchHeader.SequencerSetVerifyHash() + require.NoError(t, err) + require.NotEqual(t, common.Hash{}, cutoverSequencerHash) + + cache.batchData.Append(make([]byte, 60), []byte{1, 2, 3}, nil) + cache.postStateRoot = common.HexToHash("0x2001") + cache.withdrawRoot = common.HexToHash("0x2002") + cache.lastPackedBlockHeight++ + + index, newHeader, _, err := cache.SealBatch(1, nil) + require.NoError(t, err) + require.Equal(t, transitionCutover+1, index) + newBatch, exists := cache.GetSealedBatch(index) + require.True(t, exists) + require.True(t, bytes.Equal(headers[transitionCutover], newBatch.ParentBatchHeader), "K+1 must embed the exact canonical K header") + sequencerHash, err := newHeader.SequencerSetVerifyHash() + require.NoError(t, err) + require.Equal(t, common.Hash{}, sequencerHash, "K+1 must use the post-upgrade zero sequencer hash") +} + +func TestInitAndSyncFromDatabaseLegacyTransitionAcceptsAdvancedFinalizedWindow(t *testing.T) { + kv := openTestKV(t) + rollup, headers := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + rollup.finalized = transitionFinalized + 1 + require.NoError(t, NewBatchStorage(kv).DeleteSealedBatch(transitionFinalized)) + cache := newTransitionBatchCache(kv, rollup) + + require.NoError(t, cache.InitAndSyncFromDatabase()) + require.Equal(t, headers[transitionCutover].Bytes(), cache.parentBatchHeader.Bytes()) + for index := rollup.finalized; index <= transitionCutover; index++ { + _, exists := cache.GetSealedBatchHeader(index) + require.True(t, exists, "finalizer must retain pending canonical header %d", index) + } +} + +func TestInitAndSyncFromDatabaseLegacyTransitionFailsClosedOnUnavailableCache(t *testing.T) { + t.Run("empty database", func(t *testing.T) { + kv := openTestKV(t) + rollup := &transitionRollupReader{ + committed: transitionCutover, + finalized: transitionFinalized, + cutover: transitionCutover, + committedHash: make(map[uint64][32]byte), + batchBlockByID: make(map[uint64]uint64), + } + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + keys, scanErr := kv.IteratePrefixKeys([]byte(SealedBatchKeyPrefix)) + require.NoError(t, scanErr) + require.Empty(t, keys) + }) + + t.Run("corrupt indices", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + require.NoError(t, kv.PutBytes([]byte(SealedBatchIndicesKey), []byte("not-json"))) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover) + }) + + t.Run("missing canonical header", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + require.NoError(t, kv.Delete(encodeBatchHeaderKey(transitionCutover-1))) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover) + }) + + t.Run("explicit rebuild refuses to wipe", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + + err := newTransitionBatchCache(kv, rollup).DeleteBatchStorageAndInitFromRollup() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover) + }) +} + +func TestInitAndSyncFromDatabaseLegacyTransitionRejectsCutoverHashMismatch(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + rollup.committedHash[transitionCutover] = [32]byte(common.HexToHash("0xdeadbeef")) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover) +} + +func TestInitAndSyncFromDatabaseLegacyTransitionHandlesLocalPostCutoverBatch(t *testing.T) { + t.Run("zero sequencer hash is accepted", func(t *testing.T) { + kv := openTestKV(t) + rollup, headers := storeTransitionWindow(t, kv, transitionCutover+1, common.Hash{}) + cache := newTransitionBatchCache(kv, rollup) + + require.NoError(t, cache.InitAndSyncFromDatabase()) + require.Equal(t, headers[transitionCutover+1].Bytes(), cache.parentBatchHeader.Bytes()) + }) + + t.Run("non-zero legacy sequencer hash is rejected", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.HexToHash("0xabcdef")) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover+1) + }) +} + +func TestInitAndSyncFromDatabaseLegacyTransitionRejectsMutatedLocalBroadcastFields(t *testing.T) { + tests := []struct { + name string + mutate func(*eth.RPCRollupBatch, *BatchHeaderBytes) + }{ + { + name: "L1 message count", + mutate: func(storedBatch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { + storedBatch.NumL1Messages++ + }, + }, + { + name: "cumulative L1 messages", + mutate: func(_ *eth.RPCRollupBatch, storedHeader *BatchHeaderBytes) { + total := binary.BigEndian.Uint64((*storedHeader)[17:25]) + binary.BigEndian.PutUint64((*storedHeader)[17:25], total+1) + }, + }, + { + name: "single blob commitment", + mutate: func(storedBatch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { + storedBatch.Sidecar.Commitments[0][0] ^= 0x01 + }, + }, + { + name: "V1 multiple blobs", + mutate: func(storedBatch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { + storedBatch.Sidecar.Blobs = append(storedBatch.Sidecar.Blobs, storedBatch.Sidecar.Blobs[0]) + storedBatch.Sidecar.Commitments = append(storedBatch.Sidecar.Commitments, storedBatch.Sidecar.Commitments[0]) + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.Hash{}) + mutateStoredTransitionRecord(t, kv, transitionCutover+1, test.mutate) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover+1) + }) + } +} + +func TestInitAndSyncFromDatabaseLegacyTransitionValidatesV2AggregateBlobHash(t *testing.T) { + makeV2 := func(useAggregate bool) (SealedBatchKV, *transitionRollupReader) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.Hash{}) + mutateStoredTransitionRecord(t, kv, transitionCutover+1, func(storedBatch *eth.RPCRollupBatch, storedHeader *BatchHeaderBytes) { + storedBatch.Sidecar.Blobs = append(storedBatch.Sidecar.Blobs, storedBatch.Sidecar.Blobs[0]) + storedBatch.Sidecar.Commitments = append(storedBatch.Sidecar.Commitments, storedBatch.Sidecar.Commitments[0]) + (*storedHeader)[0] = BatchHeaderVersion2 + storedBatch.Version = uint(BatchHeaderVersion2) + blobHashes := blob.BlobHashes(storedBatch.Sidecar.Blobs, storedBatch.Sidecar.Commitments) + commitHash := blobHashes[0] + if useAggregate { + commitHash = aggregateBlobHashes(blobHashes) + } + copy((*storedHeader)[57:89], commitHash[:]) + }) + return kv, rollup + } + + t.Run("aggregate is accepted", func(t *testing.T) { + kv, rollup := makeV2(true) + require.NoError(t, newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase()) + }) + + t.Run("first blob hash is rejected", func(t *testing.T) { + kv, rollup := makeV2(false) + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionStoragePreserved(t, kv, transitionCutover+1) + }) +} + +func TestBatchCacheGetFailsClosedBeforeInitialization(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + cache := newTransitionBatchCache(kv, rollup) + + storedBatch, err := NewBatchStorage(kv).LoadSealedBatch(transitionCutover) + require.NoError(t, err) + require.NotNil(t, storedBatch, "fixture must contain the batch Get would otherwise load") + batchFromCache, err := cache.Get(transitionCutover) + require.ErrorIs(t, err, ErrBatchCacheNotInitialized) + require.Nil(t, batchFromCache) +} + +func TestInitFromRollupLegacyTransitionFailsClosed(t *testing.T) { + rollup := &transitionRollupReader{ + committed: transitionCutover, + finalized: transitionFinalized, + cutover: transitionCutover, + committedHash: make(map[uint64][32]byte), + batchBlockByID: make(map[uint64]uint64), + } + err := newTransitionBatchCache(openTestKV(t), rollup).Init() + require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) +} diff --git a/common/batch/interfaces.go b/common/batch/interfaces.go index 7dc43848d..fa634dc92 100644 --- a/common/batch/interfaces.go +++ b/common/batch/interfaces.go @@ -72,6 +72,7 @@ type RollupBatchReader interface { CommittedBatches(opts *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) + LegacyCutoverBatchIndex(opts *bind.CallOpts) (*big.Int, error) BatchDataStore(opts *bind.CallOpts, batchIndex *big.Int) (struct { OriginTimestamp *big.Int FinalizeTimestamp *big.Int diff --git a/contracts/contracts/l1/rollup/IRollup.sol b/contracts/contracts/l1/rollup/IRollup.sol index bbaa21201..5ed341cd2 100644 --- a/contracts/contracts/l1/rollup/IRollup.sol +++ b/contracts/contracts/l1/rollup/IRollup.sol @@ -121,7 +121,12 @@ interface IRollup { event ProveRemainingClaimed(address receiver, uint256 amount); /// @notice Emitted when the legacy staking dependency is replaced with Submitter. - event SubmitterContractUpdated(address indexed oldAddr, address indexed newAddr); + /// @param oldAddr The legacy staking dependency. + /// @param newAddr The new Submitter dependency. + /// @param legacyCutoverBatchIndex The last committed batch at the atomic cutover. + event SubmitterContractUpdated( + address indexed oldAddr, address indexed newAddr, uint256 indexed legacyCutoverBatchIndex + ); /// @notice Emitted when the state of Challenge is updated. /// @param batchIndex The index of the batch. @@ -150,6 +155,9 @@ interface IRollup { /// @notice The latest finalized batch index. function lastCommittedBatchIndex() external view returns (uint256); + /// @notice The last committed batch index captured by the Submitter cutover. + function legacyCutoverBatchIndex() external view returns (uint256); + /// @notice Return the batch hash of a committed batch. /// @param batchIndex The index of the batch. function committedBatches(uint256 batchIndex) external view returns (bytes32); diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 2822701b3..0e271e3b6 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -24,6 +24,10 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice The zero versioned hash. bytes32 internal constant ZERO_VERSIONED_HASH = 0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014; + /// @notice EIP-1967 storage slot containing the current proxy admin. + bytes32 private constant EIP1967_PROXY_ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable LAYER_2_CHAIN_ID; @@ -103,6 +107,10 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @dev Placed after rollupDelayPeriod for upgrade-safe storage layout (forward compatibility). mapping(uint256 batchIndex => bytes32 blobVersionedHash) public batchBlobVersionedHashes; + /// @inheritdoc IRollup + /// @dev Appended to Rollup's own storage layout. This is an audit marker; transition safety relies on the cutover runbook. + uint256 public override legacyCutoverBatchIndex; + /********************** * Function Modifiers * **********************/ @@ -196,13 +204,17 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { /// @notice One-time cutover from the legacy staking address to the Submitter proxy. /// @dev Called atomically through the existing ProxyAdmin upgradeAndCall flow. - function initialize4(address _newSubmitter) external reinitializer(4) { + /// @param _newSubmitter The new Submitter proxy. + /// @param _expectedLegacyCutoverBatchIndex The last committed batch expected by the cutover operator. + function initialize4(address _newSubmitter, uint256 _expectedLegacyCutoverBatchIndex) external reinitializer(4) { + require(_msgSender() == _getProxyAdmin(), "only proxy admin"); require(_newSubmitter != address(0) && _newSubmitter.code.length > 0, "invalid submitter"); - require(lastCommittedBatchIndex == lastFinalizedBatchIndex, "pending batches"); + require(lastCommittedBatchIndex == _expectedLegacyCutoverBatchIndex, "cutover batch mismatch"); require(!inChallenge, "challenge in progress"); require(revertReqIndex == 0, "pending revert request"); - emit SubmitterContractUpdated(submitterContract, _newSubmitter); + legacyCutoverBatchIndex = _expectedLegacyCutoverBatchIndex; + emit SubmitterContractUpdated(submitterContract, _newSubmitter, _expectedLegacyCutoverBatchIndex); submitterContract = _newSubmitter; } @@ -713,6 +725,14 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { * Internal Functions * **********************/ + /// @dev Read the current EIP-1967 admin from proxy storage. It is zero on the implementation contract. + function _getProxyAdmin() internal view returns (address admin) { + bytes32 slot = EIP1967_PROXY_ADMIN_SLOT; + assembly { + admin := sload(slot) + } + } + /// @dev Internal function to pop finalized l1 messages. /// @param totalL1MessagePopped The total number of L1 messages popped in all batches including current batch. /// @param l1MessagePopped The number of L1 messages popped in current batch. diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index 87741b2a6..cf9458712 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -2,7 +2,7 @@ pragma solidity =0.8.24; import {L1MessageBaseTest} from "./base/L1MessageBase.t.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {IRollup} from "../l1/rollup/IRollup.sol"; import {Rollup} from "../l1/rollup/Rollup.sol"; import {BatchHeaderCodecV0} from "../libraries/codec/BatchHeaderCodecV0.sol"; @@ -1359,8 +1359,24 @@ contract RollupSubmitterUpgradeTest is L1MessageBaseTest { uint256 internal constant BATCH_DATA_STORE_SLOT = 162; uint256 internal constant IN_CHALLENGE_SLOT = 166; uint256 internal constant REVERT_REQ_INDEX_SLOT = 168; + uint256 internal constant LEGACY_CUTOVER_BATCH_INDEX_SLOT = 174; + + function test_initialize4RejectsNonAdminOnFreshProxy() public { + Rollup nextImplementation = new Rollup(layer2ChainID); + TransparentUpgradeableProxy freshProxy = + new TransparentUpgradeableProxy(address(nextImplementation), address(proxyAdmin), new bytes(0)); + Rollup freshRollup = Rollup(payable(address(freshProxy))); + + hevm.prank(alice); + hevm.expectRevert("only proxy admin"); + freshRollup.initialize4(address(submitter), 0); + + assertEq(freshRollup.submitterContract(), address(0)); + assertEq(freshRollup.legacyCutoverBatchIndex(), 0); + } function test_initialize4IsAtomicThroughProxyAdminAndRunsOnce() public { + uint256 expectedCutoverBatchIndex = 7; Rollup nextImplementation = new Rollup(layer2ChainID); bytes32 batchDataBase = keccak256(abi.encode(uint256(0), BATCH_DATA_STORE_SLOT)); bytes32 legacyOwnerSlot = bytes32(uint256(batchDataBase) + 3); @@ -1368,36 +1384,43 @@ contract RollupSubmitterUpgradeTest is L1MessageBaseTest { hevm.store(address(rollup), legacyOwnerSlot, legacyValue); bytes32 storedBlobSlot = keccak256(abi.encode(uint256(7), BATCH_BLOB_VERSIONED_HASHES_SLOT)); hevm.store(address(rollup), storedBlobSlot, bytes32(uint256(0x1234))); + hevm.store(address(rollup), bytes32(LAST_FINALIZED_BATCH_INDEX_SLOT), bytes32(uint256(5))); + hevm.store(address(rollup), bytes32(LAST_COMMITTED_BATCH_INDEX_SLOT), bytes32(expectedCutoverBatchIndex)); hevm.prank(multisig); proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(payable(address(rollup))), address(nextImplementation), - abi.encodeCall(Rollup.initialize4, (address(submitter))) + abi.encodeCall(Rollup.initialize4, (address(submitter), expectedCutoverBatchIndex)) ); assertEq(rollup.submitterContract(), address(submitter)); + assertEq(rollup.lastFinalizedBatchIndex(), 5); + assertEq(rollup.lastCommittedBatchIndex(), expectedCutoverBatchIndex); + assertEq(rollup.legacyCutoverBatchIndex(), expectedCutoverBatchIndex); + assertEq( + uint256(hevm.load(address(rollup), bytes32(LEGACY_CUTOVER_BATCH_INDEX_SLOT))), expectedCutoverBatchIndex + ); assertEq(hevm.load(address(rollup), legacyOwnerSlot), legacyValue); assertEq(rollup.batchBlobVersionedHashes(7), bytes32(uint256(0x1234))); hevm.prank(multisig); hevm.expectRevert("Initializable: contract is already initialized"); - rollup.initialize4(address(submitter)); + rollup.initialize4(address(submitter), expectedCutoverBatchIndex); } - function test_initialize4ChecksDrainChallengeAndRevertBeforeCutover() public { + function test_initialize4ChecksExpectedCutoverChallengeAndRevertBeforeCutover() public { Rollup nextImplementation = new Rollup(layer2ChainID); hevm.store(address(rollup), bytes32(LAST_COMMITTED_BATCH_INDEX_SLOT), bytes32(uint256(1))); hevm.prank(multisig); - hevm.expectRevert("pending batches"); + hevm.expectRevert("cutover batch mismatch"); proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(payable(address(rollup))), address(nextImplementation), - abi.encodeCall(Rollup.initialize4, (address(submitter))) + abi.encodeCall(Rollup.initialize4, (address(submitter), 0)) ); - hevm.store(address(rollup), bytes32(LAST_COMMITTED_BATCH_INDEX_SLOT), bytes32(0)); hevm.store(address(rollup), bytes32(LAST_FINALIZED_BATCH_INDEX_SLOT), bytes32(0)); hevm.store(address(rollup), bytes32(IN_CHALLENGE_SLOT), bytes32(uint256(1))); hevm.prank(multisig); @@ -1405,7 +1428,7 @@ contract RollupSubmitterUpgradeTest is L1MessageBaseTest { proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(payable(address(rollup))), address(nextImplementation), - abi.encodeCall(Rollup.initialize4, (address(submitter))) + abi.encodeCall(Rollup.initialize4, (address(submitter), 1)) ); hevm.store(address(rollup), bytes32(IN_CHALLENGE_SLOT), bytes32(0)); @@ -1415,7 +1438,7 @@ contract RollupSubmitterUpgradeTest is L1MessageBaseTest { proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(payable(address(rollup))), address(nextImplementation), - abi.encodeCall(Rollup.initialize4, (address(submitter))) + abi.encodeCall(Rollup.initialize4, (address(submitter), 1)) ); hevm.store(address(rollup), bytes32(REVERT_REQ_INDEX_SLOT), bytes32(0)); @@ -1423,15 +1446,17 @@ contract RollupSubmitterUpgradeTest is L1MessageBaseTest { proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(payable(address(rollup))), address(nextImplementation), - abi.encodeCall(Rollup.initialize4, (address(submitter))) + abi.encodeCall(Rollup.initialize4, (address(submitter), 1)) ); assertEq(rollup.submitterContract(), address(submitter)); + assertEq(rollup.legacyCutoverBatchIndex(), 1); } function test_newSubmissionSelectors() public { assertEq(IRollup.commitBatch.selector, bytes4(0x41f756da)); assertEq(IRollup.commitState.selector, bytes4(0x67caa37a)); assertEq(IRollup.commitBatchWithProof.selector, bytes4(0x1544ba3a)); + assertEq(Rollup.initialize4.selector, bytes4(0x843bc9a1)); } } diff --git a/contracts/integration-test/upgrade_rollup_proxy.spec.ts b/contracts/integration-test/upgrade_rollup_proxy.spec.ts new file mode 100644 index 000000000..87b3fe867 --- /dev/null +++ b/contracts/integration-test/upgrade_rollup_proxy.spec.ts @@ -0,0 +1,161 @@ +import { expect } from "chai" +import { ethers, network, run } from "hardhat" + +describe("upgradeRollupProxy", () => { + const layer2ChainID = 900 + const lastFinalizedBatchIndexSlot = 157 + const lastCommittedBatchIndexSlot = 158 + const minimumStake = ethers.utils.parseEther("1") + const challengeDeposit = ethers.utils.parseEther("2") + const rewardPercentage = 25 + + async function setUintStorage(address: string, slot: number, value: number): Promise { + await network.provider.send("hardhat_setStorageAt", [ + address, + ethers.utils.hexValue(slot), + ethers.utils.hexZeroPad(ethers.utils.hexlify(value), 32), + ]) + await network.provider.send("evm_mine") + } + + async function deployPendingRollup(): Promise<{ + proxyAdminAddress: string + rollupProxyAddress: string + submitterProxyAddress: string + submitterImplementationAddress: string + activeOperatorAddress: string + inactiveOperatorAddress: string + }> { + const [owner, messageQueue, verifier, activeOperator, inactiveOperator] = await ethers.getSigners() + const rollupFactory = await ethers.getContractFactory("Rollup") + const rollupImplementation = await rollupFactory.deploy(layer2ChainID) + await rollupImplementation.deployed() + + const proxyAdminFactory = await ethers.getContractFactory("ProxyAdmin") + const proxyAdmin = await proxyAdminFactory.deploy() + await proxyAdmin.deployed() + + const initializer = rollupFactory.interface.encodeFunctionData("initialize", [ + owner.address, + messageQueue.address, + verifier.address, + 2 * 24 * 60 * 60, + 60 * 60, + 50, + ]) + const proxyFactory = await ethers.getContractFactory("TransparentUpgradeableProxy") + const rollupProxy = await proxyFactory.deploy(rollupImplementation.address, proxyAdmin.address, initializer) + await rollupProxy.deployed() + + const submitterFactory = await ethers.getContractFactory("Submitter") + const submitterImplementation = await submitterFactory.deploy() + await submitterImplementation.deployed() + const submitterInitializer = submitterFactory.interface.encodeFunctionData("initialize", [ + owner.address, + rollupProxy.address, + minimumStake, + challengeDeposit, + rewardPercentage, + ]) + const submitterProxy = await proxyFactory.deploy( + submitterImplementation.address, + proxyAdmin.address, + submitterInitializer + ) + await submitterProxy.deployed() + const submitter = await ethers.getContractAt("Submitter", submitterProxy.address) + await (await submitter.addSubmitter(activeOperator.address)).wait() + await (await submitter.connect(activeOperator).stake({ value: minimumStake })).wait() + + await setUintStorage(rollupProxy.address, lastFinalizedBatchIndexSlot, 5) + await setUintStorage(rollupProxy.address, lastCommittedBatchIndexSlot, 7) + + return { + proxyAdminAddress: proxyAdmin.address, + rollupProxyAddress: rollupProxy.address, + submitterProxyAddress: submitterProxy.address, + submitterImplementationAddress: submitterImplementation.address, + activeOperatorAddress: activeOperator.address, + inactiveOperatorAddress: inactiveOperator.address, + } + } + + it("upgrades with pending batches and persists the operator-provided cutover", async () => { + const deployment = await deployPendingRollup() + + await run("upgradeRollupProxy", { + proxyadminaddr: deployment.proxyAdminAddress, + rollupproxyaddr: deployment.rollupProxyAddress, + submitterproxyaddr: deployment.submitterProxyAddress, + submitteroperatoraddr: deployment.activeOperatorAddress, + expectedcutoverbatchindex: "7", + }) + + const rollup = await ethers.getContractAt("Rollup", deployment.rollupProxyAddress) + expect(await rollup.lastFinalizedBatchIndex()).to.equal(5) + expect(await rollup.lastCommittedBatchIndex()).to.equal(7) + expect(await rollup.legacyCutoverBatchIndex()).to.equal(7) + expect(await rollup.submitterContract()).to.equal(deployment.submitterProxyAddress) + expect(await rollup.LAYER_2_CHAIN_ID()).to.equal(layer2ChainID) + }) + + it("rejects a stale expected cutover before deploying the upgrade", async () => { + const deployment = await deployPendingRollup() + let failure: Error | undefined + + try { + await run("upgradeRollupProxy", { + proxyadminaddr: deployment.proxyAdminAddress, + rollupproxyaddr: deployment.rollupProxyAddress, + submitterproxyaddr: deployment.submitterProxyAddress, + submitteroperatoraddr: deployment.activeOperatorAddress, + expectedcutoverbatchindex: "6", + }) + } catch (error) { + failure = error as Error + } + + expect(failure).not.to.equal(undefined) + expect(failure?.message).to.contain("Rollup cutover batch mismatch: expected=6 committed=7") + }) + + it("rejects a bare Submitter implementation", async () => { + const deployment = await deployPendingRollup() + let failure: Error | undefined + + try { + await run("upgradeRollupProxy", { + proxyadminaddr: deployment.proxyAdminAddress, + rollupproxyaddr: deployment.rollupProxyAddress, + submitterproxyaddr: deployment.submitterImplementationAddress, + submitteroperatoraddr: deployment.activeOperatorAddress, + expectedcutoverbatchindex: "7", + }) + } catch (error) { + failure = error as Error + } + + expect(failure).not.to.equal(undefined) + expect(failure?.message).to.contain("Submitter rollup mismatch") + }) + + it("rejects a Submitter proxy when the supplied operator is not active", async () => { + const deployment = await deployPendingRollup() + let failure: Error | undefined + + try { + await run("upgradeRollupProxy", { + proxyadminaddr: deployment.proxyAdminAddress, + rollupproxyaddr: deployment.rollupProxyAddress, + submitterproxyaddr: deployment.submitterProxyAddress, + submitteroperatoraddr: deployment.inactiveOperatorAddress, + expectedcutoverbatchindex: "7", + }) + } catch (error) { + failure = error as Error + } + + expect(failure).not.to.equal(undefined) + expect(failure?.message).to.contain("Submitter operator is not active") + }) +}) diff --git a/contracts/tasks/README.md b/contracts/tasks/README.md index 1a095e784..cf1684624 100644 --- a/contracts/tasks/README.md +++ b/contracts/tasks/README.md @@ -25,13 +25,18 @@ or --network l1` For the one-time Rollup cutover to Submitter, use the dedicated task instead of -the generic proxy upgrade. It checks that committed batches are fully finalized, -that no challenge or revert request is pending, and then calls -`ProxyAdmin.upgradeAndCall(initialize4)` atomically: +the generic proxy upgrade. Stop legacy submissions, challenges, and revert +requests before running it. The task verifies the expected last committed batch, +requires no active challenge or revert request, and validates that the target is +an initialized Submitter proxy configured for this Rollup with valid owner and +staking parameters. The supplied operator must already be active. The task reads +the L2 chain ID from the existing Rollup, deploys the replacement with that value, +and calls `ProxyAdmin.upgradeAndCall(initialize4)` atomically: `yarn hardhat upgradeRollupProxy --proxyadminaddr \ --rollupproxyaddr --submitterproxyaddr \ ---chainid --network ` +--submitteroperatoraddr --expectedcutoverbatchindex \ +--network ` For a fresh deployment, `batchSubmitterPks` must be a JSON array whose order matches `batchSubmitterAddresses` in the selected deploy config. The `register` diff --git a/contracts/tasks/proxy_upgrade.ts b/contracts/tasks/proxy_upgrade.ts index a10a55967..665b05c6d 100644 --- a/contracts/tasks/proxy_upgrade.ts +++ b/contracts/tasks/proxy_upgrade.ts @@ -225,31 +225,47 @@ task("upgradeSystemDictatorImpl") /* One-time Submitter cutover for an existing Rollup. The task deploys the new -implementation, checks the drain gates, and calls ProxyAdmin.upgradeAndCall -with initialize4(address) in the same transaction. +implementation, checks the cutover gates, and calls ProxyAdmin.upgradeAndCall +with initialize4(address,uint256) in the same transaction. */ task("upgradeRollupProxy") .addParam("proxyadminaddr") .addParam("rollupproxyaddr") .addParam("submitterproxyaddr") - .addParam("chainid") + .addParam("submitteroperatoraddr") + .addParam("expectedcutoverbatchindex") .setAction(async (taskArgs, hre) => { if ( !hre.ethers.utils.isAddress(taskArgs.proxyadminaddr) || !hre.ethers.utils.isAddress(taskArgs.rollupproxyaddr) || - !hre.ethers.utils.isAddress(taskArgs.submitterproxyaddr) + !hre.ethers.utils.isAddress(taskArgs.submitterproxyaddr) || + !hre.ethers.utils.isAddress(taskArgs.submitteroperatoraddr) || + taskArgs.proxyadminaddr === hre.ethers.constants.AddressZero || + taskArgs.rollupproxyaddr === hre.ethers.constants.AddressZero || + taskArgs.submitterproxyaddr === hre.ethers.constants.AddressZero || + taskArgs.submitteroperatoraddr === hre.ethers.constants.AddressZero ) { - throw new Error("invalid ProxyAdmin, Rollup, or Submitter address") + throw new Error("invalid ProxyAdmin, Rollup, Submitter, or active operator address") } - const ProxyAdminFactory = await hre.ethers.getContractFactory('ProxyAdmin') + const ProxyAdminFactory = await hre.ethers.getContractFactory("ProxyAdmin") const proxyAdmin = ProxyAdminFactory.attach(taskArgs.proxyadminaddr) - const RollupFactory = await hre.ethers.getContractFactory("Rollup"); + const RollupFactory = await hre.ethers.getContractFactory("Rollup") const rollup = await hre.ethers.getContractAt("Rollup", taskArgs.rollupproxyaddr) + const layer2ChainID = await rollup.LAYER_2_CHAIN_ID() + let expectedCutover: ethers.BigNumber + try { + expectedCutover = hre.ethers.BigNumber.from(taskArgs.expectedcutoverbatchindex) + } catch { + throw new Error("invalid expected cutover batch index") + } + if (expectedCutover.lt(0)) { + throw new Error("invalid expected cutover batch index") + } const lastCommitted = await rollup.lastCommittedBatchIndex() const lastFinalized = await rollup.lastFinalizedBatchIndex() - if (!lastCommitted.eq(lastFinalized)) { - throw new Error(`Rollup is not drained: committed=${lastCommitted} finalized=${lastFinalized}`) + if (!lastCommitted.eq(expectedCutover)) { + throw new Error(`Rollup cutover batch mismatch: expected=${expectedCutover} committed=${lastCommitted}`) } if (await rollup.inChallenge()) { throw new Error("Rollup has a challenge in progress") @@ -258,24 +274,79 @@ task("upgradeRollupProxy") throw new Error("Rollup has a pending revert request") } - const rollupNewImpl = await RollupFactory.deploy(taskArgs.chainid); + const submitterCode = await hre.ethers.provider.getCode(taskArgs.submitterproxyaddr) + if (submitterCode === "0x") { + throw new Error("Submitter proxy has no code") + } + const submitter = await hre.ethers.getContractAt("Submitter", taskArgs.submitterproxyaddr) + let configuredRollup: string + let configuredOwner: string + let minimumStake: ethers.BigNumber + let challengeDeposit: ethers.BigNumber + let rewardPercentage: ethers.BigNumber + let operatorIsActive: boolean + try { + ;[configuredRollup, configuredOwner, minimumStake, challengeDeposit, rewardPercentage, operatorIsActive] = + await Promise.all([ + submitter.rollupContract(), + submitter.owner(), + submitter.minimumStake(), + submitter.challengeDeposit(), + submitter.rewardPercentage(), + submitter.isActive(taskArgs.submitteroperatoraddr), + ]) + } catch (error) { + const reason = error instanceof Error ? error.message : String(error) + throw new Error(`Submitter semantic preflight failed: ${reason}`) + } + if (configuredRollup.toLowerCase() !== taskArgs.rollupproxyaddr.toLowerCase()) { + throw new Error( + `Submitter rollup mismatch: expected=${taskArgs.rollupproxyaddr} actual=${configuredRollup}` + ) + } + if ( + configuredOwner === hre.ethers.constants.AddressZero || + minimumStake.isZero() || + challengeDeposit.isZero() || + rewardPercentage.isZero() || + rewardPercentage.gt(100) + ) { + throw new Error("Submitter owner or parameters are invalid") + } + if (!operatorIsActive) { + throw new Error(`Submitter operator is not active: ${taskArgs.submitteroperatoraddr}`) + } + + const rollupNewImpl = await RollupFactory.deploy(layer2ChainID) await rollupNewImpl.deployed() console.log("new rollupNewImpl contract address: ", rollupNewImpl.address) const initializer = RollupFactory.interface.encodeFunctionData("initialize4", [ taskArgs.submitterproxyaddr, + expectedCutover, ]) - const res = await proxyAdmin.upgradeAndCall( - taskArgs.rollupproxyaddr, - rollupNewImpl.address, - initializer - ) + const res = await proxyAdmin.upgradeAndCall(taskArgs.rollupproxyaddr, rollupNewImpl.address, initializer) const rec = await res.wait() const configuredSubmitter = await rollup.submitterContract() if (configuredSubmitter.toLowerCase() !== taskArgs.submitterproxyaddr.toLowerCase()) { throw new Error("Rollup Submitter cutover verification failed") } - console.log(`upgrade Rollup and initialize Submitter dependency ${rec.status === 1}`) + const configuredCutover = await rollup.legacyCutoverBatchIndex() + if (!configuredCutover.eq(expectedCutover)) { + throw new Error( + `Rollup legacy cutover verification failed: expected=${expectedCutover} actual=${configuredCutover}` + ) + } + const configuredChainID = await rollup.LAYER_2_CHAIN_ID() + if (!configuredChainID.eq(layer2ChainID)) { + throw new Error( + `Rollup L2 chain ID verification failed: expected=${layer2ChainID} actual=${configuredChainID}` + ) + } + console.log( + `upgrade Rollup and initialize Submitter dependency ${rec.status === 1}; ` + + `cutover=${configuredCutover} finalized=${lastFinalized} l2ChainID=${configuredChainID}` + ) }) /* diff --git a/tx-submitter/iface/rollup.go b/tx-submitter/iface/rollup.go index 36d160db7..f1caf94d3 100644 --- a/tx-submitter/iface/rollup.go +++ b/tx-submitter/iface/rollup.go @@ -13,6 +13,7 @@ import ( type IRollup interface { LastCommittedBatchIndex(opts *bind.CallOpts) (*big.Int, error) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, error) + LegacyCutoverBatchIndex(opts *bind.CallOpts) (*big.Int, error) FinalizeBatch(*bind.TransactOpts, []byte) (*types.Transaction, error) BatchInsideChallengeWindow(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) BatchExist(opts *bind.CallOpts, batchIndex *big.Int) (bool, error) diff --git a/tx-submitter/mock/rollup.go b/tx-submitter/mock/rollup.go index 288019e6a..bebf9f28e 100644 --- a/tx-submitter/mock/rollup.go +++ b/tx-submitter/mock/rollup.go @@ -16,6 +16,7 @@ import ( type MockRollup struct { lastCommittedBatchIndex *big.Int lastFinalizedBatchIndex *big.Int + legacyCutoverBatchIndex *big.Int insideChallengeWindow bool batchExists bool storedBlobHash [32]byte @@ -27,6 +28,7 @@ func NewMockRollup() *MockRollup { return &MockRollup{ lastCommittedBatchIndex: big.NewInt(0), lastFinalizedBatchIndex: big.NewInt(0), + legacyCutoverBatchIndex: big.NewInt(0), insideChallengeWindow: false, batchExists: false, } @@ -42,6 +44,11 @@ func (m *MockRollup) LastFinalizedBatchIndex(opts *bind.CallOpts) (*big.Int, err return m.lastFinalizedBatchIndex, nil } +// LegacyCutoverBatchIndex implements IRollup. +func (m *MockRollup) LegacyCutoverBatchIndex(opts *bind.CallOpts) (*big.Int, error) { + return m.legacyCutoverBatchIndex, nil +} + // FinalizeBatch implements IRollup func (m *MockRollup) FinalizeBatch(opts *bind.TransactOpts, data []byte) (*types.Transaction, error) { return m.finalizeTx, nil @@ -106,6 +113,11 @@ func (m *MockRollup) SetLastFinalizedBatchIndex(index *big.Int) { m.lastFinalizedBatchIndex = index } +// SetLegacyCutoverBatchIndex sets the immutable pre-upgrade batch boundary. +func (m *MockRollup) SetLegacyCutoverBatchIndex(index *big.Int) { + m.legacyCutoverBatchIndex = index +} + // SetBatchInsideChallengeWindow sets the mock value for BatchInsideChallengeWindow func (m *MockRollup) SetBatchInsideChallengeWindow(inside bool) { m.insideChallengeWindow = inside diff --git a/tx-submitter/services/rollup.go b/tx-submitter/services/rollup.go index ea8b762b6..dbd7a61dd 100644 --- a/tx-submitter/services/rollup.go +++ b/tx-submitter/services/rollup.go @@ -227,17 +227,6 @@ func (r *Rollup) Start() error { r.metrics.SetHasPendingFinalizeBatch(hasPendingFinalizeBatch) }) - go utils.Loop(r.ctx, r.cfg.RollupInterval, func() { - r.rollupFinalizeMu.Lock() - defer r.rollupFinalizeMu.Unlock() - if err := r.rollup(); err != nil { - if utils.IsRpcErr(err) { - r.metrics.IncRpcErrors() - } - log.Error("rollup failed,wait for the next try", "error", err) - } - }) - if r.cfg.Finalize { go utils.Loop(r.ctx, r.cfg.FinalizeInterval, func() { r.rollupFinalizeMu.Lock() @@ -266,41 +255,71 @@ func (r *Rollup) Start() error { }) if r.cfg.SealBatch { - var batchCacheSyncMu sync.Mutex + batchCacheReady := make(chan struct{}) go func() { - batchCacheSyncMu.Lock() - defer batchCacheSyncMu.Unlock() for { - - if err = r.batchCache.InitAndSyncFromDatabase(); err != nil { - log.Error("init and sync from database failed, wait for the next try", "error", err) - time.Sleep(5 * time.Second) + if initErr := r.batchCache.InitAndSyncFromDatabase(); initErr != nil { + log.Error("init and sync from database failed, wait for the next try", "error", initErr) + retry := time.NewTimer(5 * time.Second) + select { + case <-r.ctx.Done(): + retry.Stop() + return + case <-retry.C: + } continue } - break - } - }() - go utils.Loop(r.ctx, r.cfg.TxProcessInterval, func() { - batchCacheSyncMu.Lock() - defer batchCacheSyncMu.Unlock() - if err = r.batchCache.AssembleCurrentBatchHeader(); err != nil { - log.Error("assemble current batch failed, wait for the next try", "error", err) + // In SealBatch mode the commit loop must not exist before the + // migrated cache has passed transition validation. Finalization + // and pending-transaction processing are started independently + // above and remain available while initialization is retried. + close(batchCacheReady) + r.startRollupLoop() return } - if index, err := r.batchCache.LatestBatchIndex(); err != nil { - log.Error("cannot get the latest batch index from batch cache", "error", err) + }() + + go func() { + select { + case <-r.ctx.Done(): return - } else { - r.metrics.SetLastCacheBatchIndex(index) + case <-batchCacheReady: } - }) + utils.Loop(r.ctx, r.cfg.TxProcessInterval, func() { + if assembleErr := r.batchCache.AssembleCurrentBatchHeader(); assembleErr != nil { + log.Error("assemble current batch failed, wait for the next try", "error", assembleErr) + return + } + if index, err := r.batchCache.LatestBatchIndex(); err != nil { + log.Error("cannot get the latest batch index from batch cache", "error", err) + return + } else { + r.metrics.SetLastCacheBatchIndex(index) + } + }) + }() + } else { + r.startRollupLoop() } return nil } +func (r *Rollup) startRollupLoop() { + go utils.Loop(r.ctx, r.cfg.RollupInterval, func() { + r.rollupFinalizeMu.Lock() + defer r.rollupFinalizeMu.Unlock() + if err := r.rollup(); err != nil { + if utils.IsRpcErr(err) { + r.metrics.IncRpcErrors() + } + log.Error("rollup failed,wait for the next try", "error", err) + } + }) +} + func (r *Rollup) ProcessTx() error { // Check for reorgs first with exponential backoff retry hasReorg, depth, err := r.detectReorgWithRetry() diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index 20781533b..a8ec73232 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "morph-l2/bindings/bindings" + "morph-l2/common/batch" "morph-l2/tx-submitter/iface" "morph-l2/tx-submitter/metrics" "morph-l2/tx-submitter/mock" @@ -109,6 +110,26 @@ func TestPreCheckUsesSubmitterActivity(t *testing.T) { require.ErrorContains(t, r.PreCheck(), "check Submitter activity") } +func TestSealBatchRollupCannotSubmitAfterLegacyCacheInitFailure(t *testing.T) { + r, _, _, rollupContract := setupTestRollup(t) + r.cfg.SealBatch = true + rollupContract.SetLastFinalizedBatchIndex(big.NewInt(10)) + rollupContract.SetLastCommittedBatchIndex(big.NewInt(12)) + rollupContract.SetLegacyCutoverBatchIndex(big.NewInt(12)) + + initErr := r.batchCache.Init() + require.ErrorIs(t, initErr, batch.ErrLegacyTransitionCacheRequired) + cachedBatch, getErr := r.batchCache.Get(13) + require.ErrorIs(t, getErr, batch.ErrBatchCacheNotInitialized) + require.Nil(t, cachedBatch) + + // Even a direct call (defence in depth beyond Start's loop gate) cannot + // create or enqueue a commit while cache validation remains unsuccessful. + require.NoError(t, r.rollup()) + require.Zero(t, r.pendingTxs.Len()) + require.Zero(t, r.pendingTxs.GetPindex()) +} + // TestHandleDiscardedTx tests the handling of discarded transactions func TestHandleDiscardedTx(t *testing.T) { r, l1Mock, _, _ := setupTestRollup(t) From d3a356a425c90343e4a7777647dcfe4252420c29 Mon Sep 17 00:00:00 2001 From: Segue Date: Wed, 19 Aug 2026 08:44:16 +0800 Subject: [PATCH 37/38] fix(batch): rebuild cache from empty database --- common/batch/batch_cache.go | 742 ++++++++++++++++---- common/batch/batch_query.go | 3 + common/batch/batch_storage.go | 30 + common/batch/batch_transition_test.go | 480 ++++++++++++- common/batch/interfaces.go | 5 +- common/batch/l2_gov.go | 35 +- tx-submitter/services/rollup_handle_test.go | 8 +- 7 files changed, 1143 insertions(+), 160 deletions(-) diff --git a/common/batch/batch_cache.go b/common/batch/batch_cache.go index fd17727ff..1fd5499b2 100644 --- a/common/batch/batch_cache.go +++ b/common/batch/batch_cache.go @@ -16,6 +16,7 @@ import ( "github.com/morph-l2/go-ethereum/common/hexutil" ethtypes "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto" + "github.com/morph-l2/go-ethereum/crypto/kzg4844" "github.com/morph-l2/go-ethereum/eth" "github.com/morph-l2/go-ethereum/log" @@ -69,6 +70,10 @@ type BatchCache struct { l2Clients L2MultiClient rollupContract RollupBatchReader l2Gov L2GovCaller + // finalizedBatchHeaderLoader is an optional recovery seam used by tests and + // alternate canonical header sources. Production leaves it nil and loads the + // header from the L1 finalize transaction. + finalizedBatchHeaderLoader func(uint64) (*BatchHeaderBytes, error) // config batchTimeOut uint64 @@ -77,6 +82,10 @@ type BatchCache struct { // replayL1CommittedBatches is true while InitAndSyncFromRollup is rebuilding committed batches from L2. replayL1CommittedBatches atomic.Bool + // legacyCutoverBatchIndex is the last committed batch whose header contains + // the historical sequencer-set hash. It is snapshotted from L1 at startup and + // is consulted only by committed-batch replay; live sealing always writes zero. + legacyCutoverBatchIndex uint64 } type batchPackProgressState struct { @@ -89,10 +98,9 @@ const batchProgressLogStepPercent uint64 = 20 // batches already committed on L1 (independent of max_blob_count flag). const replayProtocolMaxBlobs = 6 -// ErrLegacyTransitionCacheRequired means the Rollup still has pre-upgrade, -// unfinalized batches and therefore cannot be recovered with the post-upgrade -// zero-sequencer-field replay algorithm. The canonical sealed-batch window must -// be migrated intact and startup must fail closed if it is unavailable. +// ErrLegacyTransitionCacheRequired is retained for API compatibility with older +// callers. Startup no longer returns it: a missing or invalid transition cache +// is rebuilt from canonical L1/L2 history. var ErrLegacyTransitionCacheRequired = errors.New("canonical legacy transition cache required") // ErrBatchCacheNotInitialized prevents callers from reading persisted or @@ -168,24 +176,25 @@ func (bc *BatchCache) Init() error { if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } - cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) + cutover, _, err := bc.getLegacyTransitionStatus(ci, fi) if err != nil { return err } - if transition { - return legacyTransitionCacheError( - "cannot rebuild from finalized batch %d while legacy cutover batch %d is still pending", - fi.Uint64(), - cutover, - ) - } - headerBytes, err := bc.getLastFinalizeBatchHeaderFromRollupByIndex(fi.Uint64()) + return bc.initFromRollupSnapshot(ci, fi, cutover) +} + +// initFromRollupSnapshot installs the exact finalized header as the in-memory +// replay anchor. The anchor intentionally need not be persisted: restart cache +// validation accepts a canonical window beginning at FI+1 and verifies its +// embedded parent header against the on-chain FI hash. +func (bc *BatchCache) initFromRollupSnapshot(ci, fi *big.Int, cutover uint64) error { + headerBytes, err := bc.getValidatedFinalizedBatchHeader(fi.Uint64()) if err != nil { - return fmt.Errorf("get last finalize batch header err: %w", err) + return err } - // Initialize BatchCache parent batch information - // prevStateRoot should be the parent batch's postStateRoot + // Initialize BatchCache parent batch information. + // prevStateRoot should be the parent batch's postStateRoot. prevStateRoot, err := headerBytes.PostStateRoot() if err != nil { return fmt.Errorf("get post state root err: %w", err) @@ -208,11 +217,76 @@ func (bc *BatchCache) Init() error { bc.lastPackedBlockHeight = lastPackedBlockHeight bc.currentBlockNumber = lastPackedBlockHeight bc.totalL1MessagePopped = totalL1MessagePopped + bc.legacyCutoverBatchIndex = cutover bc.mu.Unlock() log.Info("Start assemble batch", "start batch", fi.Uint64(), "end batch", ci.Uint64()) return nil } +func (bc *BatchCache) getValidatedFinalizedBatchHeader(finalized uint64) (*BatchHeaderBytes, error) { + var ( + headerBytes *BatchHeaderBytes + err error + ) + if bc.finalizedBatchHeaderLoader != nil { + headerBytes, err = bc.finalizedBatchHeaderLoader(finalized) + } else { + if bc.l1Client == nil { + return nil, errors.New("cannot load finalized batch header: nil L1 client") + } + headerBytes, err = bc.getLastFinalizeBatchHeaderFromRollupByIndex(finalized) + } + if err != nil { + return nil, fmt.Errorf("get last finalize batch header err: %w", err) + } + if headerBytes == nil { + return nil, fmt.Errorf("finalized batch header %d is nil", finalized) + } + headerIndex, err := headerBytes.BatchIndex() + if err != nil { + return nil, fmt.Errorf("get finalized batch header index: %w", err) + } + if headerIndex != finalized { + return nil, fmt.Errorf("finalized batch anchor index mismatch: expected %d, got %d", finalized, headerIndex) + } + headerHash, err := headerBytes.Hash() + if err != nil { + return nil, fmt.Errorf("hash finalized batch anchor %d: %w", finalized, err) + } + committedHash, err := bc.rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(finalized)) + if err != nil { + return nil, fmt.Errorf("load committed hash for finalized batch %d: %w", finalized, err) + } + if headerHash != common.Hash(committedHash) { + return nil, fmt.Errorf( + "finalized batch anchor %d hash mismatch: L1 calldata=%s committed=%s", + finalized, headerHash, common.Hash(committedHash), + ) + } + return headerBytes, nil +} + +// resetForRollupReplay removes unvalidated runtime state left by a prior failed +// replay attempt. Persisted state is wiped separately by the recovery path. +func (bc *BatchCache) resetForRollupReplay() { + bc.mu.Lock() + defer bc.mu.Unlock() + bc.initDone = false + bc.sealedBatches = make(map[uint64]*eth.RPCRollupBatch) + bc.sealedBatchHeaders = make(map[uint64]*BatchHeaderBytes) + bc.parentBatchHeader = nil + bc.prevStateRoot = common.Hash{} + bc.batchData = NewBatchData() + bc.totalL1MessagePopped = 0 + bc.postStateRoot = common.Hash{} + bc.withdrawRoot = common.Hash{} + bc.lastPackedBlockHeight = 0 + bc.currentBlockNumber = 0 + bc.currentBlockHash = common.Hash{} + bc.legacyCutoverBatchIndex = 0 + bc.ClearCurrent() +} + func (bc *BatchCache) isInitialized() bool { bc.mu.RLock() defer bc.mu.RUnlock() @@ -231,7 +305,21 @@ func (bc *BatchCache) InitFromRollupByRange() error { if bc.isInitialized() { return nil } - err := bc.Init() + ci, fi, err := bc.getBatchStatusFromContract() + if err != nil { + return fmt.Errorf("get batch status from rollup failed err: %w", err) + } + _, transition, err := bc.getLegacyTransitionStatus(ci, fi) + if err != nil { + return err + } + if transition { + // Range assembly seals by local capacity and uses the live zero-field + // format. During the transition, committed batches must instead be + // replayed by their exact L1 batch ranges with historical sequencer data. + return bc.initAndSyncFromRollupLocked() + } + err = bc.Init() if err != nil { return err } @@ -266,14 +354,24 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { fmt.Errorf("load sealed batch headers: %w", err), ) } + if err := bc.batchStorage.ValidateExactKeySet(indices); err != nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("validate sealed batch storage key set: %w", err), + ) + } if len(batches) == 0 { - if transition { - return legacyTransitionCacheError( - "empty sealed-batch storage for pending legacy window [%d,%d]", - fi.Uint64(), - cutover, - ) + log.Info("Empty sealed batch cache; rebuilding from rollup", + "finalizedBatchIndex", fi.Uint64(), + "committedBatchIndex", ci.Uint64(), + "legacyTransition", transition, + "legacyCutoverBatchIndex", cutover, + ) + // An absent/empty indices snapshot can hide orphan batch keys. Always + // prefix-wipe before an empty-cache rebuild so those keys cannot survive. + if err := bc.batchStorage.ForceDeleteAllSealedBatches(); err != nil { + return fmt.Errorf("wipe empty/orphaned sealed batch cache: %w", err) } return bc.initAndSyncFromRollupLocked() } @@ -283,19 +381,44 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { errors.New("sealed batches exist without an indices snapshot"), ) } - if transition { - if err := validateLegacyTransitionWindow(batches, headers, indices, fi.Uint64(), ci.Uint64(), cutover); err != nil { - return legacyTransitionCacheError("invalid migrated cache: %v", err) - } - } maxIndex := indices[0] for _, idx := range indices { if idx > maxIndex { maxIndex = idx } } - // check batch hash with the batch that already rollup by submitter - for i := fi.Uint64(); i <= ci.Uint64(); i++ { + if maxIndex < fi.Uint64() { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("latest cached batch %d is behind finalized batch %d", maxIndex, fi.Uint64()), + ) + } + var finalizedAnchor *BatchHeaderBytes + if _, hasFinalizedRecord := batches[fi.Uint64()]; !hasFinalizedRecord { + anchor, err := bc.getValidatedFinalizedBatchHeader(fi.Uint64()) + if err != nil { + // This is an L1 availability/canonical-data failure, not evidence that + // the local cache is corrupt. Leave the cache untouched and retry. + return fmt.Errorf("validate finalized cache anchor: %w", err) + } + if err := validateCachedWindowAgainstFinalizedAnchor(batches, headers, fi.Uint64(), ci.Uint64(), anchor); err != nil { + return bc.handleInvalidStoredBatchCache(transition, err) + } + finalizedAnchor = anchor + } + if transition { + if err := validateLegacyTransitionWindow(batches, headers, indices, fi.Uint64(), ci.Uint64(), cutover); err != nil { + return bc.handleInvalidStoredBatchCache(transition, fmt.Errorf("invalid transition cache: %w", err)) + } + } + // Check every persisted committed batch. A replay-built cache starts at FI+1 + // because FI is loaded as an exact L1 anchor and is not written to LevelDB; + // migrated caches that still contain FI remain valid and are checked too. + firstCommitted := fi.Uint64() + 1 + if _, exists := batches[fi.Uint64()]; exists { + firstCommitted = fi.Uint64() + } + for i := firstCommitted; i <= ci.Uint64(); i++ { batchHash, err := bc.rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(i)) if err != nil { return err @@ -308,9 +431,86 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { fmt.Errorf("batch %d missing or does not match committed hash", i), ) } + if i > cutover { + header := headers[i] + if header == nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("committed post-cutover batch header %d is missing", i), + ) + } + sequencerHash, err := header.SequencerSetVerifyHash() + if err != nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("read committed batch %d sequencer-set hash: %w", i, err), + ) + } + if sequencerHash != (common.Hash{}) { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("committed batch %d is beyond cutover %d but has non-zero sequencer-set hash %s", i, cutover, sequencerHash), + ) + } + } + } + // Records above CI are locally sealed and may be broadcast after startup, so + // validate every calldata/blob-derived field before accepting them. Since the + // cutover is never ahead of CI, all such records must carry the new zero + // sequencer-set field regardless of whether FI has already crossed K. + for _, index := range indices { + if index <= ci.Uint64() { + continue + } + batch := batches[index] + header := headers[index] + if batch == nil || header == nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("local batch %d or its header is missing", index), + ) + } + if err := validateLegacyTransitionRecord(index, batch, header, true); err != nil { + return bc.handleInvalidStoredBatchCache(transition, err) + } + sequencerHash, err := header.SequencerSetVerifyHash() + if err != nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("read local batch %d sequencer-set hash: %w", index, err), + ) + } + if sequencerHash != (common.Hash{}) { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("local post-cutover batch %d has non-zero sequencer-set hash %s", index, sequencerHash), + ) + } } latestHeaderBytes := headers[maxIndex] + if latestHeaderBytes == nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("latest cached batch header %d is missing", maxIndex), + ) + } + latestHeaderIndex, err := latestHeaderBytes.BatchIndex() + if err != nil { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf("read latest cached batch header index: %w", err), + ) + } + if latestHeaderIndex != maxIndex || latestHeaderIndex < fi.Uint64() { + return bc.handleInvalidStoredBatchCache( + transition, + fmt.Errorf( + "latest cached header index %d does not match storage max %d/finalized %d", + latestHeaderIndex, maxIndex, fi.Uint64(), + ), + ) + } prevStateRoot, err := latestHeaderBytes.PostStateRoot() if err != nil { return bc.handleInvalidStoredBatchCache( @@ -354,6 +554,22 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { } lastPackedBlockHeight = store.BlockNumber.Uint64() } + if err := bc.ensureRecoverySnapshotUnchanged(ci, fi, cutover); err != nil { + // A concurrent commit/finalize changes which records are canonical/local. + // Do not wipe a cache that was valid for the original snapshot; retry the + // complete validation against the new tuple instead. + return err + } + committedTip := headers[ci.Uint64()] + if committedTip == nil && ci.Cmp(fi) == 0 { + committedTip = finalizedAnchor + } + if err := bc.validateCommittedTip(ci.Uint64(), committedTip); err != nil { + // Keep the DB intact on an RPC or same-index canonical-view change. The + // next startup attempt will validate the whole window against that view + // and rebuild if the change is stable. + return fmt.Errorf("revalidate cached committed tip: %w", err) + } bc.mu.Lock() bc.lastPackedBlockHeight = lastPackedBlockHeight bc.sealedBatches = batches @@ -362,6 +578,7 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { bc.currentBlockNumber = bc.lastPackedBlockHeight bc.prevStateRoot = prevStateRoot bc.totalL1MessagePopped = totalL1MessagePopped + bc.legacyCutoverBatchIndex = cutover bc.initDone = true bc.mu.Unlock() @@ -374,63 +591,223 @@ func (bc *BatchCache) InitAndSyncFromDatabase() error { return nil } +func validateCachedWindowAgainstFinalizedAnchor( + batches map[uint64]*eth.RPCRollupBatch, + headers map[uint64]*BatchHeaderBytes, + finalized uint64, + committed uint64, + anchor *BatchHeaderBytes, +) error { + if anchor == nil { + return errors.New("finalized batch anchor is nil") + } + anchorIndex, err := anchor.BatchIndex() + if err != nil { + return fmt.Errorf("read finalized batch anchor index: %w", err) + } + if anchorIndex != finalized { + return fmt.Errorf("finalized anchor index mismatch: expected %d, got %d", finalized, anchorIndex) + } + anchorHash, err := anchor.Hash() + if err != nil { + return fmt.Errorf("hash finalized batch anchor %d: %w", finalized, err) + } + + childIndex := finalized + 1 + child := batches[childIndex] + if child == nil { + return fmt.Errorf( + "non-empty cache without finalized batch %d must begin at canonical child %d (committed=%d)", + finalized, childIndex, committed, + ) + } + if !bytes.Equal(child.ParentBatchHeader, anchor.Bytes()) { + return fmt.Errorf("batch %d does not embed the exact finalized L1 header %d", childIndex, finalized) + } + childHeader := headers[childIndex] + if childHeader == nil { + return fmt.Errorf("batch header %d is missing", childIndex) + } + childParentHash, err := childHeader.ParentBatchHash() + if err != nil { + return fmt.Errorf("read batch %d parent hash: %w", childIndex, err) + } + if childParentHash != anchorHash { + return fmt.Errorf( + "batch %d parent hash mismatch: header=%s finalized-anchor=%s", + childIndex, childParentHash, anchorHash, + ) + } + return nil +} + func (bc *BatchCache) InitAndSyncFromRollup() error { bc.initMu.Lock() defer bc.initMu.Unlock() return bc.initAndSyncFromRollupLocked() } -func (bc *BatchCache) initAndSyncFromRollupLocked() error { +func (bc *BatchCache) initAndSyncFromRollupLocked() (retErr error) { if bc.isInitialized() { return nil } bc.replayL1CommittedBatches.Store(true) defer bc.replayL1CommittedBatches.Store(false) - err := bc.Init() - if err != nil { - return err - } ci, fi, err := bc.getBatchStatusFromContract() if err != nil { return fmt.Errorf("get batch status from rollup failed err: %w", err) } + cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) + if err != nil { + return err + } + bc.resetForRollupReplay() + defer func() { + if retErr == nil { + return + } + // A replay publishes only batches whose index and L1 hash have already + // been verified, but an incomplete prefix is not a valid startup cache. + // Remove it from both runtime and storage before the next retry. + bc.resetForRollupReplay() + if err := bc.batchStorage.ForceDeleteAllSealedBatches(); err != nil { + retErr = fmt.Errorf("%v; cleanup failed: %w", retErr, err) + } + }() + if err := bc.initFromRollupSnapshot(ci, fi, cutover); err != nil { + return err + } log.Info("Start assemble batch", "startBatch", fi.Uint64()+1, "endBatch", ci.Uint64(), "startNum", bc.lastPackedBlockHeight, "prevStateRoot", bc.prevStateRoot.String(), + "legacyTransition", transition, + "legacyCutoverBatchIndex", cutover, ) - for i := fi.Uint64() + 1; i <= ci.Uint64(); i++ { - batchIndex := new(big.Int).SetUint64(i) - startNum, endNum, err := bc.getBatchBlockRange(batchIndex) - if err != nil { - return fmt.Errorf("get batch block range err: %w,start %v, end %v", err, startNum, endNum) + nextBatch := fi.Uint64() + 1 + targetCI := new(big.Int).Set(ci) + observedFI := new(big.Int).Set(fi) + for { + for i := nextBatch; i <= targetCI.Uint64(); i++ { + batchIndex := new(big.Int).SetUint64(i) + startNum, endNum, err := bc.getBatchBlockRange(batchIndex) + if err != nil { + return fmt.Errorf("get batch block range err: %w,start %v, end %v", err, startNum, endNum) + } + log.Info("assemble batch block range", "startNum", startNum, "endNum", endNum) + replayIdx := i + header, err := bc.assembleBatchHeaderFromL2Blocks(startNum, endNum, &replayIdx) + if err != nil { + return err + } + // sealBatch has already checked generated index and committedBatches + // before publishing. Log the exact format branch and reconciliation. + sequencerHash, err := header.SequencerSetVerifyHash() + if err != nil { + return fmt.Errorf("read replay batch %d sequencer-set hash: %w", i, err) + } + batchHash, err := header.Hash() + if err != nil { + return fmt.Errorf("hash replay batch %d: %w", i, err) + } + log.Info("Replayed committed batch", + "batchIndex", i, + "legacySequencerSet", i <= cutover, + "sequencerSetVerifyHash", sequencerHash, + "generatedBatchHash", batchHash, + "committedBatchHash", batchHash, + "targetCommittedBatchIndex", targetCI, + ) } - log.Info("assemble batch block range", "startNum", startNum, "endNum", endNum) - replayIdx := i - batchHeaderBytes, err := bc.assembleBatchHeaderFromL2Blocks(startNum, endNum, &replayIdx) + + latestCI, latestFI, err := bc.getBatchStatusFromContract() if err != nil { - return err + return fmt.Errorf("recheck batch status after replay: %w", err) } - batchHash, err := batchHeaderBytes.Hash() + latestCutover, _, err := bc.getLegacyTransitionStatus(latestCI, latestFI) if err != nil { - return fmt.Errorf("get batch hash err: %w", err) + return fmt.Errorf("recheck legacy cutover after replay: %w", err) } - correct, err := bc.checkBatchHashCorrect(batchIndex, batchHash) - if err != nil { - return fmt.Errorf("check batch hash failed, err: %w, batchIndex %v, batchHash %v", err, batchIndex, batchHash.String()) + if latestCutover != cutover || latestCI.Cmp(targetCI) < 0 || latestFI.Cmp(observedFI) < 0 { + return fmt.Errorf( + "rollup recovery state regressed or cutover changed: previous=(FI=%s CI=%s K=%d) latest=(FI=%s CI=%s K=%d)", + observedFI, targetCI, cutover, latestFI, latestCI, latestCutover, + ) } - if !correct { - return fmt.Errorf("batch hash check failed: batch index %d is incorrect", i) + if latestCI.Cmp(targetCI) == 0 { + bc.mu.RLock() + committedTip := bc.parentBatchHeader + bc.mu.RUnlock() + if err := bc.validateCommittedTip(targetCI.Uint64(), committedTip); err != nil { + return fmt.Errorf("revalidate replayed committed tip: %w", err) + } + break } - log.Info("Assemble batch success", "batch index", i, "last batch index", ci.Uint64()) + log.Info("Committed batch index advanced during recovery; continuing incremental replay", + "fromBatch", targetCI.Uint64()+1, + "toBatch", latestCI.Uint64(), + "latestFinalizedBatchIndex", latestFI, + ) + nextBatch = targetCI.Uint64() + 1 + targetCI.Set(latestCI) + observedFI.Set(latestFI) } bc.setInitialized() log.Info("Initialized batch cache success") return nil } +func (bc *BatchCache) ensureRecoverySnapshotUnchanged(ci, fi *big.Int, cutover uint64) error { + latestCI, latestFI, err := bc.getBatchStatusFromContract() + if err != nil { + return fmt.Errorf("recheck batch status after recovery: %w", err) + } + latestCutover, _, err := bc.getLegacyTransitionStatus(latestCI, latestFI) + if err != nil { + return fmt.Errorf("recheck legacy cutover after recovery: %w", err) + } + if latestCI.Cmp(ci) != 0 || latestFI.Cmp(fi) != 0 || latestCutover != cutover { + return fmt.Errorf( + "rollup recovery snapshot changed: start=(FI=%s CI=%s K=%d) end=(FI=%s CI=%s K=%d)", + fi, ci, cutover, latestFI, latestCI, latestCutover, + ) + } + return nil +} + +// validateCommittedTip closes the same-index reorg/revert window left by an +// FI/CI/K tuple check. Since each batch hash commits to its parent, matching the +// current L1 tip authenticates the complete reconstructed prefix. +func (bc *BatchCache) validateCommittedTip(index uint64, header *BatchHeaderBytes) error { + if header == nil { + return fmt.Errorf("committed tip header %d is missing", index) + } + headerIndex, err := header.BatchIndex() + if err != nil { + return fmt.Errorf("read committed tip header index: %w", err) + } + if headerIndex != index { + return fmt.Errorf("committed tip index mismatch: expected %d, got %d", index, headerIndex) + } + headerHash, err := header.Hash() + if err != nil { + return fmt.Errorf("hash committed tip %d: %w", index, err) + } + committedHash, err := bc.rollupContract.CommittedBatches(nil, new(big.Int).SetUint64(index)) + if err != nil { + return fmt.Errorf("load current committed tip %d: %w", index, err) + } + if headerHash != common.Hash(committedHash) { + return fmt.Errorf( + "committed tip %d changed without an index change: cached=%s current=%s", + index, headerHash, common.Hash(committedHash), + ) + } + return nil +} + func (bc *BatchCache) LatestBatchIndex() (uint64, error) { return bc.parentBatchHeader.BatchIndex() } @@ -459,6 +836,21 @@ func (bc *BatchCache) getBatchStatusFromContract() (*big.Int, *big.Int, error) { if err != nil { return nil, nil, err } + if latestCommitBatchIndex == nil || lastFinalizedBatchIndex == nil { + return nil, nil, errors.New("rollup returned nil batch status") + } + if latestCommitBatchIndex.Sign() < 0 || lastFinalizedBatchIndex.Sign() < 0 { + return nil, nil, fmt.Errorf( + "rollup returned negative batch status: committed=%s finalized=%s", + latestCommitBatchIndex, lastFinalizedBatchIndex, + ) + } + if lastFinalizedBatchIndex.Cmp(latestCommitBatchIndex) > 0 { + return nil, nil, fmt.Errorf( + "last finalized batch %s is ahead of last committed batch %s", + lastFinalizedBatchIndex, latestCommitBatchIndex, + ) + } return latestCommitBatchIndex, lastFinalizedBatchIndex, nil } @@ -480,23 +872,15 @@ func (bc *BatchCache) getLegacyTransitionStatus(ci, fi *big.Int) (uint64, bool, return cutover.Uint64(), fi.Cmp(cutover) < 0, nil } -func legacyTransitionCacheError(format string, args ...interface{}) error { - return fmt.Errorf("%w: %s", ErrLegacyTransitionCacheRequired, fmt.Sprintf(format, args...)) -} - -func (bc *BatchCache) handleInvalidStoredBatchCache(transition bool, cause error) error { - if transition { - return legacyTransitionCacheError("%v", cause) - } +func (bc *BatchCache) handleInvalidStoredBatchCache(_ bool, cause error) error { log.Error("Invalid sealed batch cache; rebuilding from rollup", "error", cause) return bc.deleteBatchStorageAndInitFromRollupLocked() } // validateLegacyTransitionWindow applies the additional invariants needed while -// a pre-upgrade batch remains unfinalized. LoadAllSealedBatchesAndHeader already -// checks the persisted parent chain and header hashes; this function makes sure -// the complete canonical on-chain window is present and prevents pre-upgrade, -// locally sealed batches beyond the cutover from becoming post-upgrade parents. +// a pre-upgrade batch remains unfinalized. The finalized batch itself is an L1 +// anchor and may be absent from LevelDB; in that case the persisted canonical +// window must begin at FI+1, whose embedded parent header is validated below. func validateLegacyTransitionWindow( batches map[uint64]*eth.RPCRollupBatch, headers map[uint64]*BatchHeaderBytes, @@ -512,7 +896,11 @@ func validateLegacyTransitionWindow( return fmt.Errorf("legacy cutover %d is ahead of committed batch %d", cutover, committed) } - for idx := finalized; ; idx++ { + canonicalStart := finalized + if batches[finalized] == nil { + canonicalStart = finalized + 1 + } + for idx := canonicalStart; ; idx++ { batch := batches[idx] if batch == nil { return fmt.Errorf("canonical batch %d is missing", idx) @@ -692,6 +1080,15 @@ func validateLegacyTransitionRecord( len(batch.Sidecar.Commitments), ) } + for i := range batch.Sidecar.Blobs { + commitment, err := kzg4844.BlobToCommitment(&batch.Sidecar.Blobs[i]) + if err != nil { + return fmt.Errorf("batch %d blob %d is invalid: %w", index, i, err) + } + if commitment != batch.Sidecar.Commitments[i] { + return fmt.Errorf("batch %d blob %d does not match its stored commitment", index, i) + } + } blobHashes := blob.BlobHashes(batch.Sidecar.Blobs, batch.Sidecar.Commitments) var sidecarCommitHash common.Hash if version >= BatchHeaderVersion2 { @@ -785,14 +1182,10 @@ func (bc *BatchCache) GetSealedBatch(batchIndex uint64) (*eth.RPCRollupBatch, bo func (bc *BatchCache) GetSealedBatchHeader(batchIndex uint64) (*BatchHeaderBytes, bool) { bc.mu.RLock() defer bc.mu.RUnlock() - header, ok := bc.sealedBatchHeaders[batchIndex] - if !ok { - loadedHeader, err := bc.batchStorage.LoadSealedBatchHeader(batchIndex) - if err != nil { - return nil, false - } - return loadedHeader, true + if !bc.initDone { + return nil, false } + header, ok := bc.sealedBatchHeaders[batchIndex] return header, ok } @@ -981,6 +1374,36 @@ func (bc *BatchCache) FetchAndCacheHeader(blockNumber uint64, withdrawRoot commo // from L1 (InitAndSyncFromRollup). After V2 multi-blob, blob capacity is capped at replayProtocolMaxBlobs // (6), not max_blob_count, without querying L1 CommitBatch logs. func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex *uint64) (uint64, BatchHeaderBytes, bool, error) { + var ( + sequencerSetBytes []byte + sequencerSetHash common.Hash + ) + if replayCommittedBatchIndex != nil { + bc.mu.RLock() + lastBlock := bc.lastPackedBlockHeight + bc.mu.RUnlock() + var err error + sequencerSetBytes, sequencerSetHash, err = bc.getReplaySequencerSet(&bind.CallOpts{ + Context: bc.ctx, + BlockNumber: new(big.Int).SetUint64(lastBlock), + }, replayCommittedBatchIndex) + if err != nil { + return 0, BatchHeaderBytes{}, false, err + } + } + return bc.sealBatch(blockTimestamp, replayCommittedBatchIndex, sequencerSetBytes, sequencerSetHash) +} + +// sealBatch is the common sealing implementation. sequencerSetBytes/hash are +// accepted only for replay of canonical batches at or before the legacy +// cutover. The live SealBatch path (nil replay index) always supplies an empty +// set and therefore always produces a zero sequencer-set field. +func (bc *BatchCache) sealBatch( + blockTimestamp uint64, + replayCommittedBatchIndex *uint64, + sequencerSetBytes []byte, + sequencerSetVerifyHash common.Hash, +) (uint64, BatchHeaderBytes, bool, error) { bc.mu.Lock() defer bc.mu.Unlock() @@ -1021,8 +1444,33 @@ func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex "sidecarCapacityBytes", effectiveBlobCount*blob.MaxBlobBytesSize, ) - // Create batch header - batchHeader := bc.createBatchHeader(batchDataHash, sidecar, blockTimestamp) + if replayCommittedBatchIndex == nil { + if len(sequencerSetBytes) != 0 || sequencerSetVerifyHash != (common.Hash{}) { + return 0, BatchHeaderBytes{}, false, errors.New("live batch cannot contain a sequencer-set hash") + } + } else if *replayCommittedBatchIndex <= bc.legacyCutoverBatchIndex { + calculated := crypto.Keccak256Hash(sequencerSetBytes) + if len(sequencerSetBytes) == 0 || calculated != sequencerSetVerifyHash { + return 0, BatchHeaderBytes{}, false, fmt.Errorf( + "replay batch %d has invalid legacy sequencer set: bytes=%d contract=%s calculated=%s", + *replayCommittedBatchIndex, len(sequencerSetBytes), sequencerSetVerifyHash, calculated, + ) + } + } else if len(sequencerSetBytes) != 0 || sequencerSetVerifyHash != (common.Hash{}) { + return 0, BatchHeaderBytes{}, false, fmt.Errorf( + "replay batch %d is beyond legacy cutover %d but has a sequencer-set hash", + *replayCommittedBatchIndex, bc.legacyCutoverBatchIndex, + ) + } + + // Create batch header. Only canonical legacy replay can supply a non-zero + // sequencer-set hash; normal live sealing reaches this function with zero. + batchHeader := bc.createBatchHeaderWithSequencerSetHash( + batchDataHash, + sidecar, + sequencerSetVerifyHash, + blockTimestamp, + ) // Calculate batch hash batchHash, err := batchHeader.Hash() @@ -1035,6 +1483,24 @@ func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex if err != nil { return 0, BatchHeaderBytes{}, false, fmt.Errorf("failed to get batch index: %w", err) } + if replayCommittedBatchIndex != nil && batchIndex != *replayCommittedBatchIndex { + return 0, BatchHeaderBytes{}, false, fmt.Errorf( + "replay batch index mismatch: expected %d, generated %d", + *replayCommittedBatchIndex, batchIndex, + ) + } + if replayCommittedBatchIndex != nil { + correct, err := bc.checkBatchHashCorrect(new(big.Int).SetUint64(batchIndex), batchHash) + if err != nil { + return 0, BatchHeaderBytes{}, false, fmt.Errorf("check replay batch %d hash: %w", batchIndex, err) + } + if !correct { + return 0, BatchHeaderBytes{}, false, fmt.Errorf( + "replay batch hash mismatch: batch index %d, generated %s", + batchIndex, batchHash, + ) + } + } // Build parent batch header bytes var parentBatchHeaderBytes hexutil.Bytes @@ -1060,16 +1526,17 @@ func (bc *BatchCache) SealBatch(blockTimestamp uint64, replayCommittedBatchIndex // Store sealed batch information as RPCRollupBatch sealedBatch := ð.RPCRollupBatch{ - Version: uint(version), - Hash: batchHash, - ParentBatchHeader: parentBatchHeaderBytes, - BlockContexts: blockContexts, - PrevStateRoot: bc.prevStateRoot, - PostStateRoot: bc.postStateRoot, - WithdrawRoot: bc.withdrawRoot, - LastBlockNumber: bc.lastPackedBlockHeight, - NumL1Messages: numL1Messages, - Sidecar: *sidecar, + Version: uint(version), + Hash: batchHash, + ParentBatchHeader: parentBatchHeaderBytes, + BlockContexts: blockContexts, + CurrentSequencerSetBytes: hexutil.Bytes(sequencerSetBytes), + PrevStateRoot: bc.prevStateRoot, + PostStateRoot: bc.postStateRoot, + WithdrawRoot: bc.withdrawRoot, + LastBlockNumber: bc.lastPackedBlockHeight, + NumL1Messages: numL1Messages, + Sidecar: *sidecar, } bc.sealedBatches[batchIndex] = sealedBatch // Store batch header copy @@ -1211,6 +1678,15 @@ func (bc *BatchCache) handleBatchSealing(blockTimestamp uint64, sealBlobCap int, // createBatchHeader creates BatchHeader func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes.BlobTxSidecar, blockTimestamp uint64) BatchHeaderBytes { + return bc.createBatchHeaderWithSequencerSetHash(dataHash, sidecar, common.Hash{}, blockTimestamp) +} + +func (bc *BatchCache) createBatchHeaderWithSequencerSetHash( + dataHash common.Hash, + sidecar *ethtypes.BlobTxSidecar, + sequencerSetVerifyHash common.Hash, + blockTimestamp uint64, +) BatchHeaderBytes { blobHashes := []common.Hash{blob.EmptyVersionedHash} if sidecar != nil && len(sidecar.Blobs) > 0 { blobHashes = sidecar.BlobHashes() @@ -1237,7 +1713,7 @@ func (bc *BatchCache) createBatchHeader(dataHash common.Hash, sidecar *ethtypes. PrevStateRoot: bc.prevStateRoot, PostStateRoot: bc.postStateRoot, WithdrawalRoot: bc.withdrawRoot, - SequencerSetVerifyHash: common.Hash{}, + SequencerSetVerifyHash: sequencerSetVerifyHash, ParentBatchHash: parentBatchHash, } @@ -1409,6 +1885,15 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( } } + var ( + sequencerSetBytes []byte + sequencerSetVerifyHash common.Hash + ) + sequencerSetBytes, sequencerSetVerifyHash, err := bc.getReplaySequencerSet(callOpts, replayCommittedBatchIndex) + if err != nil { + return nil, err + } + // Get the last block's timestamp for packing lastBlock, err := bc.l2Clients.BlockByNumber(ctx, big.NewInt(int64(endBlockNum))) if err != nil { @@ -1417,7 +1902,12 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( blockTimestamp := lastBlock.Time() // Seal batch and generate batchHeader - batchIndex, batchHeader, reachedExpectedSize, err := bc.SealBatch(blockTimestamp, replayCommittedBatchIndex) + batchIndex, batchHeader, reachedExpectedSize, err := bc.sealBatch( + blockTimestamp, + replayCommittedBatchIndex, + sequencerSetBytes, + sequencerSetVerifyHash, + ) if err != nil { return nil, fmt.Errorf("failed to seal batch: %w", err) } @@ -1430,6 +1920,36 @@ func (bc *BatchCache) assembleBatchHeaderFromL2Blocks( return &batchHeader, nil } +func (bc *BatchCache) getReplaySequencerSet( + callOpts *bind.CallOpts, + replayCommittedBatchIndex *uint64, +) ([]byte, common.Hash, error) { + if replayCommittedBatchIndex == nil || *replayCommittedBatchIndex > bc.legacyCutoverBatchIndex { + return nil, common.Hash{}, nil + } + if bc.l2Gov == nil { + return nil, common.Hash{}, fmt.Errorf( + "replay batch %d requires historical L2 sequencer state, but L2 gov caller is nil", + *replayCommittedBatchIndex, + ) + } + sequencerSetBytes, sequencerSetVerifyHash, err := bc.l2Gov.GetSequencerSetBytes(callOpts) + if err != nil { + return nil, common.Hash{}, fmt.Errorf( + "failed to get sequencer set at block %s for replay batch %d: %w", + callOpts.BlockNumber, *replayCommittedBatchIndex, err, + ) + } + calculated := crypto.Keccak256Hash(sequencerSetBytes) + if calculated != sequencerSetVerifyHash { + return nil, common.Hash{}, fmt.Errorf( + "sequencer set hash mismatch at block %s for replay batch %d: contract=%s calculated=%s", + callOpts.BlockNumber, *replayCommittedBatchIndex, sequencerSetVerifyHash, calculated, + ) + } + return sequencerSetBytes, sequencerSetVerifyHash, nil +} + func (bc *BatchCache) assembleUnFinalizeBatchHeaderFromL2Blocks() error { ctx := context.Background() callOpts := &bind.CallOpts{ @@ -1558,12 +2078,8 @@ func (bc *BatchCache) Get(batchIndex uint64) (*eth.RPCRollupBatch, error) { return nil, ErrBatchCacheNotInitialized } batch, ok := bc.sealedBatches[batchIndex] - var err error if !ok { - batch, err = bc.batchStorage.LoadSealedBatch(batchIndex) - if err != nil { - return nil, err - } + return nil, fmt.Errorf("sealed batch %d not found in validated cache: %w", batchIndex, ErrKeyNotFound) } return batch, nil } @@ -1576,6 +2092,9 @@ func (bc *BatchCache) Get(batchIndex uint64) (*eth.RPCRollupBatch, error) { func (bc *BatchCache) Delete(batchIndex uint64) error { bc.mu.Lock() defer bc.mu.Unlock() + if err := bc.batchStorage.DeleteSealedBatch(batchIndex); err != nil { + return err + } _, exists := bc.sealedBatches[batchIndex] if exists { delete(bc.sealedBatches, batchIndex) @@ -1584,10 +2103,6 @@ func (bc *BatchCache) Delete(batchIndex uint64) error { if headerExists { delete(bc.sealedBatchHeaders, batchIndex) } - err := bc.batchStorage.DeleteSealedBatch(batchIndex) - if err != nil { - return err - } return nil } @@ -1875,33 +2390,14 @@ func (bc *BatchCache) DeleteBatchStorageAndInitFromRollup() error { } func (bc *BatchCache) deleteBatchStorageAndInitFromRollupLocked() error { - ci, fi, err := bc.getBatchStatusFromContract() - if err != nil { - return fmt.Errorf("get batch status before sealed-batch wipe: %w", err) - } - cutover, transition, err := bc.getLegacyTransitionStatus(ci, fi) - if err != nil { - return err - } - if transition { - return legacyTransitionCacheError( - "refusing to wipe canonical cache while pending legacy window [%d,%d] must be preserved", - fi.Uint64(), - cutover, - ) - } - - // should delete invalid batch data and batch header bytes - if err := bc.batchStorage.DeleteAllSealedBatches(); err != nil { - // DeleteAllSealedBatches relies on a parseable sealed_batch_indices to - // enumerate keys. When that snapshot itself is corrupt the normal wipe - // can never succeed and self-heal would loop forever, so fall back to a - // prefix-scan force wipe that does not depend on the indices snapshot. - log.Warn("normal sealed-batch wipe failed during self-heal, falling back to force wipe", "error", err) - if ferr := bc.batchStorage.ForceDeleteAllSealedBatches(); ferr != nil { - return fmt.Errorf("force wipe sealed batches failed (after normal wipe error: %v): %w", err, ferr) - } - } - // batch not contiguous or batch is invalid + // Recovery always scans the prefix directly. A parseable indices snapshot + // can still omit orphan data/header keys, which DeleteAllSealedBatches would + // leave behind and could re-surface on a later repair. + if err := bc.batchStorage.ForceDeleteAllSealedBatches(); err != nil { + return fmt.Errorf("force wipe sealed batches failed: %w", err) + } + // Rebuild the complete committed window from the exact finalized L1 anchor. + // Runtime state is reset inside initAndSyncFromRollupLocked so a failed prior + // attempt cannot become the parent of this replay. return bc.initAndSyncFromRollupLocked() } diff --git a/common/batch/batch_query.go b/common/batch/batch_query.go index e150e080f..a096f5215 100644 --- a/common/batch/batch_query.go +++ b/common/batch/batch_query.go @@ -53,6 +53,9 @@ func (bc *BatchCache) getLastFinalizeBatchHeaderFromRollupByIndex(index uint64) endBlock = startBlock - 1 continue } + if finalizeEventIter == nil { + return nil, fmt.Errorf("filter finalized batch %d returned a nil iterator", index) + } defer func() { _ = finalizeEventIter.Close() }() // Iterate through query results for finalizeEventIter.Next() { diff --git a/common/batch/batch_storage.go b/common/batch/batch_storage.go index 723d53935..2a112ad57 100644 --- a/common/batch/batch_storage.go +++ b/common/batch/batch_storage.go @@ -374,6 +374,36 @@ func (s *BatchStorage) ForceDeleteAllSealedBatches() error { return nil } +// ValidateExactKeySet ensures the indices snapshot enumerates every persisted +// sealed-batch data/header key and no orphan key can bypass startup validation. +func (s *BatchStorage) ValidateExactKeySet(indices []uint64) error { + s.mu.RLock() + defer s.mu.RUnlock() + + keys, err := s.db.IteratePrefixKeys([]byte(SealedBatchKeyPrefix)) + if err != nil { + return fmt.Errorf("failed to scan sealed batch keys: %w", err) + } + expected := make(map[string]struct{}, len(indices)*2+1) + if len(indices) != 0 { + expected[SealedBatchIndicesKey] = struct{}{} + } + for _, index := range indices { + expected[string(encodeBatchKey(index))] = struct{}{} + expected[string(encodeBatchHeaderKey(index))] = struct{}{} + } + for _, key := range keys { + if _, ok := expected[string(key)]; !ok { + return fmt.Errorf("orphan sealed batch key %x is not listed in the indices snapshot", key) + } + delete(expected, string(key)) + } + if len(expected) != 0 { + return fmt.Errorf("sealed batch indices snapshot references %d missing persisted keys", len(expected)) + } + return nil +} + // encodeBatchKey encodes batch index to a byte key func encodeBatchKey(batchIndex uint64) []byte { key := make([]byte, len(SealedBatchKeyPrefix)+8) diff --git a/common/batch/batch_transition_test.go b/common/batch/batch_transition_test.go index 646286100..6bf839308 100644 --- a/common/batch/batch_transition_test.go +++ b/common/batch/batch_transition_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/binary" + "fmt" "math/big" "testing" @@ -14,6 +15,7 @@ import ( "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/common/hexutil" ethtypes "github.com/morph-l2/go-ethereum/core/types" + "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/eth" "github.com/stretchr/testify/require" ) @@ -24,18 +26,76 @@ const ( ) type transitionRollupReader struct { - committed uint64 - finalized uint64 - cutover uint64 - committedHash map[uint64][32]byte - batchBlockByID map[uint64]uint64 + committed uint64 + committedReads int + committedSequence []uint64 + finalized uint64 + cutover uint64 + committedHash map[uint64][32]byte + committedHashSeries map[uint64][][32]byte + batchBlockByID map[uint64]uint64 +} + +type transitionReplayL2Client struct { + blocks map[uint64]*ethtypes.Block +} + +func (c *transitionReplayL2Client) BlockNumber(context.Context) (uint64, error) { + var latest uint64 + for number := range c.blocks { + if number > latest { + latest = number + } + } + return latest, nil +} + +func (c *transitionReplayL2Client) BlockByNumber(_ context.Context, number *big.Int) (*ethtypes.Block, error) { + block := c.blocks[number.Uint64()] + if block == nil { + return nil, fmt.Errorf("test L2 block %d not found", number.Uint64()) + } + return block, nil +} + +func (c *transitionReplayL2Client) Len() int { return 1 } + +type transitionReplayL2Gov struct { + roots map[uint64]common.Hash + sequencerSetByBlock map[uint64][]byte + sequencerCalls []uint64 +} + +func (g *transitionReplayL2Gov) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) { + return [32]byte(g.roots[opts.BlockNumber.Uint64()]), nil +} + +func (g *transitionReplayL2Gov) GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) { + blockNumber := opts.BlockNumber.Uint64() + g.sequencerCalls = append(g.sequencerCalls, blockNumber) + setBytes := append([]byte(nil), g.sequencerSetByBlock[blockNumber]...) + return setBytes, crypto.Keccak256Hash(setBytes), nil } func (r *transitionRollupReader) CommittedBatches(_ *bind.CallOpts, batchIndex *big.Int) ([32]byte, error) { - return r.committedHash[batchIndex.Uint64()], nil + index := batchIndex.Uint64() + if series := r.committedHashSeries[index]; len(series) != 0 { + result := series[0] + r.committedHashSeries[index] = series[1:] + return result, nil + } + return r.committedHash[index], nil } func (r *transitionRollupReader) LastCommittedBatchIndex(_ *bind.CallOpts) (*big.Int, error) { + if len(r.committedSequence) != 0 { + position := r.committedReads + if position >= len(r.committedSequence) { + position = len(r.committedSequence) - 1 + } + r.committedReads++ + return new(big.Int).SetUint64(r.committedSequence[position]), nil + } return new(big.Int).SetUint64(r.committed), nil } @@ -179,12 +239,18 @@ func storeTransitionWindow( return rollup, headers } -func requireTransitionStoragePreserved(t *testing.T, kv SealedBatchKV, index uint64) { +func requireTransitionStorageCleared(t *testing.T, kv SealedBatchKV) { t.Helper() - _, err := kv.GetBytes(encodeBatchKey(index)) - require.NoError(t, err) - _, err = kv.GetBytes([]byte(SealedBatchIndicesKey)) + keys, err := kv.IteratePrefixKeys([]byte(SealedBatchKeyPrefix)) require.NoError(t, err) + require.Empty(t, keys) +} + +func requireTransitionRecoveryAttempted(t *testing.T, err error) { + t.Helper() + require.Error(t, err) + require.NotErrorIs(t, err, ErrLegacyTransitionCacheRequired) + require.ErrorContains(t, err, "nil L1 client") } func mutateStoredTransitionRecord( @@ -252,7 +318,7 @@ func TestInitAndSyncFromDatabaseLegacyTransitionAcceptsAdvancedFinalizedWindow(t } } -func TestInitAndSyncFromDatabaseLegacyTransitionFailsClosedOnUnavailableCache(t *testing.T) { +func TestInitAndSyncFromDatabaseLegacyTransitionRebuildsUnavailableCache(t *testing.T) { t.Run("empty database", func(t *testing.T) { kv := openTestKV(t) rollup := &transitionRollupReader{ @@ -264,10 +330,8 @@ func TestInitAndSyncFromDatabaseLegacyTransitionFailsClosedOnUnavailableCache(t } err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - keys, scanErr := kv.IteratePrefixKeys([]byte(SealedBatchKeyPrefix)) - require.NoError(t, scanErr) - require.Empty(t, keys) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) t.Run("corrupt indices", func(t *testing.T) { @@ -276,8 +340,8 @@ func TestInitAndSyncFromDatabaseLegacyTransitionFailsClosedOnUnavailableCache(t require.NoError(t, kv.PutBytes([]byte(SealedBatchIndicesKey), []byte("not-json"))) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) t.Run("missing canonical header", func(t *testing.T) { @@ -286,17 +350,17 @@ func TestInitAndSyncFromDatabaseLegacyTransitionFailsClosedOnUnavailableCache(t require.NoError(t, kv.Delete(encodeBatchHeaderKey(transitionCutover-1))) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) - t.Run("explicit rebuild refuses to wipe", func(t *testing.T) { + t.Run("explicit rebuild wipes before replay", func(t *testing.T) { kv := openTestKV(t) rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) err := newTransitionBatchCache(kv, rollup).DeleteBatchStorageAndInitFromRollup() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) } @@ -306,8 +370,8 @@ func TestInitAndSyncFromDatabaseLegacyTransitionRejectsCutoverHashMismatch(t *te rollup.committedHash[transitionCutover] = [32]byte(common.HexToHash("0xdeadbeef")) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) } func TestInitAndSyncFromDatabaseLegacyTransitionHandlesLocalPostCutoverBatch(t *testing.T) { @@ -325,8 +389,8 @@ func TestInitAndSyncFromDatabaseLegacyTransitionHandlesLocalPostCutoverBatch(t * rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.HexToHash("0xabcdef")) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover+1) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) } @@ -354,6 +418,13 @@ func TestInitAndSyncFromDatabaseLegacyTransitionRejectsMutatedLocalBroadcastFiel storedBatch.Sidecar.Commitments[0][0] ^= 0x01 }, }, + { + name: "blob payload does not match commitment", + mutate: func(storedBatch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { + // Keep the field element canonical while changing the blob opening. + storedBatch.Sidecar.Blobs[0][31] ^= 0x01 + }, + }, { name: "V1 multiple blobs", mutate: func(storedBatch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { @@ -370,12 +441,124 @@ func TestInitAndSyncFromDatabaseLegacyTransitionRejectsMutatedLocalBroadcastFiel mutateStoredTransitionRecord(t, kv, transitionCutover+1, test.mutate) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover+1) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) } } +func TestInitAndSyncFromDatabasePostTransitionRejectsInvalidLocalBatch(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.Hash{}) + rollup.finalized = transitionCutover + mutateStoredTransitionRecord(t, kv, transitionCutover+1, func(batch *eth.RPCRollupBatch, _ *BatchHeaderBytes) { + batch.NumL1Messages++ + }) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) +} + +func TestInitAndSyncFromDatabasePostTransitionRejectsNonZeroCommittedField(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover+1, common.HexToHash("0xabcdef")) + rollup.finalized = transitionCutover + rollup.committed = transitionCutover + 1 + committedBatch, err := NewBatchStorage(kv).LoadSealedBatch(transitionCutover + 1) + require.NoError(t, err) + rollup.committedHash[transitionCutover+1] = [32]byte(committedBatch.Hash) + + err = newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) +} + +func TestInitAndSyncFromDatabaseRejectsOrphanKeysAndGettersTrustOnlyValidatedMemory(t *testing.T) { + writeOrphan := func(t *testing.T, kv SealedBatchKV, source, orphan uint64) { + t.Helper() + batchBytes, err := kv.GetBytes(encodeBatchKey(source)) + require.NoError(t, err) + headerBytes, err := kv.GetBytes(encodeBatchHeaderKey(source)) + require.NoError(t, err) + require.NoError(t, kv.PutBytes(encodeBatchKey(orphan), batchBytes)) + require.NoError(t, kv.PutBytes(encodeBatchHeaderKey(orphan), headerBytes)) + } + + t.Run("startup rejects orphan key", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + writeOrphan(t, kv, transitionCutover, transitionCutover+100) + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) + }) + + t.Run("runtime getters ignore raw orphan key", func(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + cache := newTransitionBatchCache(kv, rollup) + require.NoError(t, cache.InitAndSyncFromDatabase()) + orphan := transitionCutover + 100 + writeOrphan(t, kv, transitionCutover, orphan) + + batch, err := cache.Get(orphan) + require.ErrorIs(t, err, ErrKeyNotFound) + require.Nil(t, batch) + header, ok := cache.GetSealedBatchHeader(orphan) + require.False(t, ok) + require.Nil(t, header) + }) +} + +func TestInitAndSyncFromDatabaseRejectsCacheBehindFinalizedIndex(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + rollup.finalized = transitionCutover + 1 + rollup.committed = transitionCutover + 1 + rollup.committedHash[transitionCutover+1] = [32]byte(common.HexToHash("0x1234")) + rollup.batchBlockByID[transitionCutover+1] = (transitionCutover + 1) * 10 + + err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) +} + +func TestInitAndSyncFromDatabaseSnapshotChangeKeepsValidatedDBForRetry(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + rollup.committedSequence = []uint64{transitionCutover, transitionCutover + 1} + + cache := newTransitionBatchCache(kv, rollup) + err := cache.InitAndSyncFromDatabase() + require.ErrorContains(t, err, "rollup recovery snapshot changed") + require.False(t, cache.isInitialized()) + stored, loadErr := NewBatchStorage(kv).LoadSealedBatch(transitionCutover) + require.NoError(t, loadErr) + require.NotNil(t, stored, "a concurrent status change is not cache corruption and must not wipe DB") +} + +func TestInitAndSyncFromDatabaseRejectsSameIndexCommittedTipChange(t *testing.T) { + kv := openTestKV(t) + rollup, _ := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + originalTip := rollup.committedHash[transitionCutover] + rollup.committedHashSeries = map[uint64][][32]byte{ + transitionCutover: { + originalTip, + [32]byte(common.HexToHash("0xdeadbeef")), + }, + } + + cache := newTransitionBatchCache(kv, rollup) + err := cache.InitAndSyncFromDatabase() + require.ErrorContains(t, err, "committed tip 12 changed without an index change") + require.False(t, cache.isInitialized()) + stored, loadErr := NewBatchStorage(kv).LoadSealedBatch(transitionCutover) + require.NoError(t, loadErr) + require.NotNil(t, stored, "a changing canonical view must be retried before deciding whether to rebuild") +} + func TestInitAndSyncFromDatabaseLegacyTransitionValidatesV2AggregateBlobHash(t *testing.T) { makeV2 := func(useAggregate bool) (SealedBatchKV, *transitionRollupReader) { kv := openTestKV(t) @@ -403,8 +586,8 @@ func TestInitAndSyncFromDatabaseLegacyTransitionValidatesV2AggregateBlobHash(t * t.Run("first blob hash is rejected", func(t *testing.T) { kv, rollup := makeV2(false) err := newTransitionBatchCache(kv, rollup).InitAndSyncFromDatabase() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) - requireTransitionStoragePreserved(t, kv, transitionCutover+1) + requireTransitionRecoveryAttempted(t, err) + requireTransitionStorageCleared(t, kv) }) } @@ -419,9 +602,12 @@ func TestBatchCacheGetFailsClosedBeforeInitialization(t *testing.T) { batchFromCache, err := cache.Get(transitionCutover) require.ErrorIs(t, err, ErrBatchCacheNotInitialized) require.Nil(t, batchFromCache) + headerFromCache, ok := cache.GetSealedBatchHeader(transitionCutover) + require.False(t, ok) + require.Nil(t, headerFromCache) } -func TestInitFromRollupLegacyTransitionFailsClosed(t *testing.T) { +func TestInitFromRollupLegacyTransitionStartsRecovery(t *testing.T) { rollup := &transitionRollupReader{ committed: transitionCutover, finalized: transitionFinalized, @@ -430,5 +616,235 @@ func TestInitFromRollupLegacyTransitionFailsClosed(t *testing.T) { batchBlockByID: make(map[uint64]uint64), } err := newTransitionBatchCache(openTestKV(t), rollup).Init() - require.ErrorIs(t, err, ErrLegacyTransitionCacheRequired) + requireTransitionRecoveryAttempted(t, err) +} + +func TestReplayBuiltTransitionWindowMayStartAfterFinalizedAnchor(t *testing.T) { + kv := openTestKV(t) + rollup, expectedHeaders := storeTransitionWindow(t, kv, transitionCutover, common.Hash{}) + storage := NewBatchStorage(kv) + require.NoError(t, storage.DeleteSealedBatch(transitionFinalized)) + + batches, headers, indices, err := storage.LoadAllSealedBatchesAndHeader() + require.NoError(t, err) + anchor := expectedHeaders[transitionFinalized] + require.NoError(t, validateCachedWindowAgainstFinalizedAnchor( + batches, + headers, + transitionFinalized, + rollup.committed, + &anchor, + )) + require.NoError(t, validateLegacyTransitionWindow( + batches, + headers, + indices, + transitionFinalized, + rollup.committed, + transitionCutover, + )) + + mutated := *batches[transitionFinalized+1] + mutated.ParentBatchHeader = append(hexutil.Bytes(nil), mutated.ParentBatchHeader...) + mutated.ParentBatchHeader[len(mutated.ParentBatchHeader)-1] ^= 0x01 + batches[transitionFinalized+1] = &mutated + err = validateCachedWindowAgainstFinalizedAnchor( + batches, + headers, + transitionFinalized, + rollup.committed, + &anchor, + ) + require.ErrorContains(t, err, "exact finalized L1 header") +} + +func TestBatchHeaderSequencerHashIsRestrictedToLegacyReplay(t *testing.T) { + cache := newTransitionBatchCache(openTestKV(t), &transitionRollupReader{}) + parent := makeTransitionHeader(transitionFinalized, common.Hash{}, common.HexToHash("0x01"), blob.EmptyVersionedHash) + cache.parentBatchHeader = &parent + cache.totalL1MessagePopped = transitionFinalized + 101 + legacyHash := common.HexToHash("0x1234") + + legacyHeader := cache.createBatchHeaderWithSequencerSetHash(common.HexToHash("0xaa"), nil, legacyHash, 1) + gotLegacyHash, err := legacyHeader.SequencerSetVerifyHash() + require.NoError(t, err) + require.Equal(t, legacyHash, gotLegacyHash) + + liveHeader := cache.createBatchHeader(common.HexToHash("0xbb"), nil, 1) + gotLiveHash, err := liveHeader.SequencerSetVerifyHash() + require.NoError(t, err) + require.Equal(t, common.Hash{}, gotLiveHash) +} + +func TestEmptyTransitionDatabaseRebuildsAndRestartsFromFIPlusOne(t *testing.T) { + const ( + finalized = uint64(10) + cutover = uint64(12) + committed = uint64(13) + ) + + rollup := &transitionRollupReader{ + committed: committed, + finalized: finalized, + cutover: cutover, + committedHash: make(map[uint64][32]byte), + batchBlockByID: make(map[uint64]uint64), + } + for index := finalized; index <= committed; index++ { + rollup.batchBlockByID[index] = index - finalized + } + + anchor := makeTransitionHeader( + finalized, + common.HexToHash("0x1000"), + common.HexToHash("0x2000"), + blob.EmptyVersionedHash, + ) + binary.BigEndian.PutUint64(anchor[len(anchor)-8:], 0) + anchorHash, err := anchor.Hash() + require.NoError(t, err) + rollup.committedHash[finalized] = [32]byte(anchorHash) + + blocks := make(map[uint64]*ethtypes.Block) + roots := make(map[uint64]common.Hash) + sequencerSets := make(map[uint64][]byte) + for index := finalized + 1; index <= committed; index++ { + blockNumber := index - finalized + blocks[blockNumber] = ethtypes.NewBlockWithHeader(ðtypes.Header{ + Number: new(big.Int).SetUint64(blockNumber), + Time: 1_000 + index, + Root: common.BigToHash(new(big.Int).SetUint64(index*100 + 1)), + }) + roots[blockNumber] = common.BigToHash(new(big.Int).SetUint64(index*100 + 2)) + if index <= cutover { + sequencerSets[blockNumber] = []byte(fmt.Sprintf("historical-sequencer-set-%d", index)) + } + } + l2Client := &transitionReplayL2Client{blocks: blocks} + + // Build the canonical committed hashes with the same deterministic packing + // primitives. This is independent of the recovery loop and lets the test + // exercise its pre-persistence committedBatches checks. + expected := newTransitionBatchCache(openTestKV(t), rollup) + expected.l2Clients = l2Client + expected.parentBatchHeader = &anchor + expected.prevStateRoot, err = anchor.PostStateRoot() + require.NoError(t, err) + expected.totalL1MessagePopped, err = anchor.TotalL1MessagePopped() + require.NoError(t, err) + expected.lastPackedBlockHeight = 0 + expected.legacyCutoverBatchIndex = cutover + expectedHeaders := make(map[uint64]BatchHeaderBytes) + for index := finalized + 1; index <= committed; index++ { + blockNumber := index - finalized + expected.batchData = NewBatchData() + expected.ClearCurrent() + _, err = expected.CalculateCapWithProposalBlock(blockNumber, roots[blockNumber]) + require.NoError(t, err) + require.NoError(t, expected.PackCurrentBlock(blockNumber)) + replayIndex := index + blobCap := expected.sealEffectiveBlobCount(blocks[blockNumber].Time(), &replayIndex) + payload, dataHash, blobCap, err := expected.handleBatchSealing(blocks[blockNumber].Time(), blobCap, &replayIndex) + require.NoError(t, err) + sidecar, err := blob.MakeBlobTxSidecar(payload, blobCap) + require.NoError(t, err) + sequencerHash := common.Hash{} + if index <= cutover { + sequencerHash = crypto.Keccak256Hash(sequencerSets[blockNumber]) + } + header := expected.createBatchHeaderWithSequencerSetHash(dataHash, sidecar, sequencerHash, blocks[blockNumber].Time()) + hash, err := header.Hash() + require.NoError(t, err) + rollup.committedHash[index] = [32]byte(hash) + expectedHeaders[index] = header + headerCopy := append(BatchHeaderBytes(nil), header...) + expected.parentBatchHeader = &headerCopy + expected.prevStateRoot = expected.postStateRoot + } + + badRollup := *rollup + badRollup.committedHash = make(map[uint64][32]byte, len(rollup.committedHash)) + for index, hash := range rollup.committedHash { + badRollup.committedHash[index] = hash + } + badRollup.committedHash[cutover] = [32]byte(common.HexToHash("0xdeadbeef")) + badKV := openTestKV(t) + badCache := newTransitionBatchCache(badKV, &badRollup) + badCache.l2Clients = l2Client + badCache.l2Gov = &transitionReplayL2Gov{roots: roots, sequencerSetByBlock: sequencerSets} + badCache.finalizedBatchHeaderLoader = func(index uint64) (*BatchHeaderBytes, error) { + copyOfAnchor := append(BatchHeaderBytes(nil), anchor...) + return ©OfAnchor, nil + } + err = badCache.InitAndSyncFromDatabase() + require.ErrorContains(t, err, "replay batch hash mismatch") + require.False(t, badCache.isInitialized()) + _, ok := badCache.GetSealedBatchHeader(finalized + 1) + require.False(t, ok, "partial replay headers must remain unpublished") + requireTransitionStorageCleared(t, badKV) + + advancingRollup := *rollup + advancingRollup.committedSequence = []uint64{cutover, cutover, committed, committed} + advancingRollup.committedReads = 0 + advancingKV := openTestKV(t) + advancingGov := &transitionReplayL2Gov{roots: roots, sequencerSetByBlock: sequencerSets} + advancingCache := newTransitionBatchCache(advancingKV, &advancingRollup) + advancingCache.l2Clients = l2Client + advancingCache.l2Gov = advancingGov + advancingCache.finalizedBatchHeaderLoader = func(index uint64) (*BatchHeaderBytes, error) { + copyOfAnchor := append(BatchHeaderBytes(nil), anchor...) + return ©OfAnchor, nil + } + require.NoError(t, advancingCache.InitAndSyncFromDatabase()) + latestAdvancedIndex, err := advancingCache.LatestBatchIndex() + require.NoError(t, err) + require.Equal(t, committed, latestAdvancedIndex, "CI growth during replay must be caught up incrementally") + require.Equal(t, []uint64{1, 2}, advancingGov.sequencerCalls) + + kv := openTestKV(t) + l2Gov := &transitionReplayL2Gov{roots: roots, sequencerSetByBlock: sequencerSets} + cache := newTransitionBatchCache(kv, rollup) + cache.l2Clients = l2Client + cache.l2Gov = l2Gov + cache.finalizedBatchHeaderLoader = func(index uint64) (*BatchHeaderBytes, error) { + require.Equal(t, finalized, index) + copyOfAnchor := append(BatchHeaderBytes(nil), anchor...) + return ©OfAnchor, nil + } + + require.NoError(t, cache.InitAndSyncFromDatabase()) + require.True(t, cache.isInitialized()) + require.Equal(t, []uint64{1, 2}, l2Gov.sequencerCalls, "only batches at or before K read historical sequencer state") + for index := finalized + 1; index <= committed; index++ { + header, ok := cache.GetSealedBatchHeader(index) + require.True(t, ok) + require.Equal(t, expectedHeaders[index].Bytes(), header.Bytes()) + sequencerHash, err := header.SequencerSetVerifyHash() + require.NoError(t, err) + batch, ok := cache.GetSealedBatch(index) + require.True(t, ok) + if index <= cutover { + require.Equal(t, crypto.Keccak256Hash(sequencerSets[index-finalized]), sequencerHash) + require.Equal(t, sequencerSets[index-finalized], []byte(batch.CurrentSequencerSetBytes)) + } else { + require.Equal(t, common.Hash{}, sequencerHash) + require.Empty(t, batch.CurrentSequencerSetBytes) + } + } + + // FI is intentionally absent on disk. A second process must accept the + // canonical [FI+1, CI] window and take the DB fast path without touching L2. + restartGov := &transitionReplayL2Gov{roots: roots, sequencerSetByBlock: sequencerSets} + restarted := newTransitionBatchCache(kv, rollup) + restarted.l2Clients = l2Client + restarted.l2Gov = restartGov + restarted.finalizedBatchHeaderLoader = cache.finalizedBatchHeaderLoader + require.NoError(t, restarted.InitAndSyncFromDatabase()) + require.True(t, restarted.isInitialized()) + require.Empty(t, restartGov.sequencerCalls) + latestIndex, err := restarted.LatestBatchIndex() + require.NoError(t, err) + require.Equal(t, committed, latestIndex) + _, err = NewBatchStorage(kv).LoadSealedBatch(finalized) + require.ErrorIs(t, err, ErrKeyNotFound) } diff --git a/common/batch/interfaces.go b/common/batch/interfaces.go index fa634dc92..ec9530f7a 100644 --- a/common/batch/interfaces.go +++ b/common/batch/interfaces.go @@ -82,7 +82,10 @@ type RollupBatchReader interface { FilterFinalizeBatch(opts *bind.FilterOpts, batchIndex []*big.Int, batchHash [][32]byte) (*bindings.RollupFinalizeBatchIterator, error) } -// L2GovCaller reads the withdrawal tree root used when assembling batches. +// L2GovCaller reads historical withdrawal and sequencer-set state used when +// replaying committed batches. Live post-cutover sealing does not read the +// sequencer contract. type L2GovCaller interface { GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) + GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) } diff --git a/common/batch/l2_gov.go b/common/batch/l2_gov.go index 641d81312..b099c4ddc 100644 --- a/common/batch/l2_gov.go +++ b/common/batch/l2_gov.go @@ -1,17 +1,21 @@ package batch import ( + "bytes" "fmt" "morph-l2/bindings/bindings" "morph-l2/bindings/predeploys" "github.com/morph-l2/go-ethereum/accounts/abi/bind" + "github.com/morph-l2/go-ethereum/common" + "github.com/morph-l2/go-ethereum/common/hexutil" + "github.com/morph-l2/go-ethereum/crypto" ) -// L2Gov provides the withdrawal-root read used when assembling rollup batches. -// The name is kept to avoid a broad caller rename during this cleanup. +// L2Gov provides the historical L2 reads used when assembling rollup batches. type L2Gov struct { + sequencerContract *bindings.SequencerCaller l2MessagePasserContract *bindings.L2ToL1MessagePasserCaller } @@ -20,11 +24,16 @@ func NewL2Gov(backend bind.ContractCaller) (*L2Gov, error) { if backend == nil { return nil, fmt.Errorf("nil contract backend") } + sequencerContract, err := bindings.NewSequencerCaller(predeploys.SequencerAddr, backend) + if err != nil { + return nil, err + } l2MessagePasserContract, err := bindings.NewL2ToL1MessagePasserCaller(predeploys.L2ToL1MessagePasserAddr, backend) if err != nil { return nil, err } return &L2Gov{ + sequencerContract: sequencerContract, l2MessagePasserContract: l2MessagePasserContract, }, nil } @@ -33,3 +42,25 @@ func NewL2Gov(backend bind.ContractCaller) (*L2Gov, error) { func (c *L2Gov) GetTreeRoot(opts *bind.CallOpts) ([32]byte, error) { return c.l2MessagePasserContract.GetTreeRoot(opts) } + +// GetSequencerSetBytes returns the historical sequencer-set encoding and hash +// at opts.BlockNumber. The two contract reads are checked against each other so +// replay never accepts bytes from a different L2 state. +func (c *L2Gov) GetSequencerSetBytes(opts *bind.CallOpts) ([]byte, common.Hash, error) { + hash, err := c.sequencerContract.SequencerSetVerifyHash(opts) + if err != nil { + return nil, common.Hash{}, err + } + setBytes, err := c.sequencerContract.GetSequencerSetBytes(opts) + if err != nil { + return nil, common.Hash{}, err + } + calculated := crypto.Keccak256Hash(setBytes) + if !bytes.Equal(hash[:], calculated[:]) { + return nil, common.Hash{}, fmt.Errorf( + "sequencer set hash verify failed: bytes=%s contract=%s calculated=%s", + hexutil.Encode(setBytes), common.Hash(hash), calculated, + ) + } + return setBytes, common.Hash(hash), nil +} diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index a8ec73232..0a47c872a 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -110,7 +110,7 @@ func TestPreCheckUsesSubmitterActivity(t *testing.T) { require.ErrorContains(t, r.PreCheck(), "check Submitter activity") } -func TestSealBatchRollupCannotSubmitAfterLegacyCacheInitFailure(t *testing.T) { +func TestSealBatchRollupCannotSubmitWhileCacheRebuildFails(t *testing.T) { r, _, _, rollupContract := setupTestRollup(t) r.cfg.SealBatch = true rollupContract.SetLastFinalizedBatchIndex(big.NewInt(10)) @@ -118,10 +118,14 @@ func TestSealBatchRollupCannotSubmitAfterLegacyCacheInitFailure(t *testing.T) { rollupContract.SetLegacyCutoverBatchIndex(big.NewInt(12)) initErr := r.batchCache.Init() - require.ErrorIs(t, initErr, batch.ErrLegacyTransitionCacheRequired) + require.Error(t, initErr) + require.NotErrorIs(t, initErr, batch.ErrLegacyTransitionCacheRequired) cachedBatch, getErr := r.batchCache.Get(13) require.ErrorIs(t, getErr, batch.ErrBatchCacheNotInitialized) require.Nil(t, cachedBatch) + cachedHeader, ok := r.batchCache.GetSealedBatchHeader(13) + require.False(t, ok) + require.Nil(t, cachedHeader) // Even a direct call (defence in depth beyond Start's loop gate) cannot // create or enqueue a commit while cache validation remains unsuccessful. From 91f26724fcf22e9036ad10e01059f87b5653fbff Mon Sep 17 00:00:00 2001 From: Segue Date: Wed, 19 Aug 2026 13:41:28 +0800 Subject: [PATCH 38/38] fix(tx-submitter): correct lint spelling --- tx-submitter/services/rollup_handle_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tx-submitter/services/rollup_handle_test.go b/tx-submitter/services/rollup_handle_test.go index 0a47c872a..ca9cb8db0 100644 --- a/tx-submitter/services/rollup_handle_test.go +++ b/tx-submitter/services/rollup_handle_test.go @@ -127,7 +127,7 @@ func TestSealBatchRollupCannotSubmitWhileCacheRebuildFails(t *testing.T) { require.False(t, ok) require.Nil(t, cachedHeader) - // Even a direct call (defence in depth beyond Start's loop gate) cannot + // Even a direct call (defense in depth beyond Start's loop gate) cannot // create or enqueue a commit while cache validation remains unsuccessful. require.NoError(t, r.rollup()) require.Zero(t, r.pendingTxs.Len())

    0mX2s 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�fMenSSl)o%#F5i2KT3h-f`SQ)%>dA$WNeQ<;$ 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 diff --git a/prover/bin/server/src/queue.rs b/prover/bin/server/src/queue.rs index b8ae27237..219a50e69 100644 --- a/prover/bin/server/src/queue.rs +++ b/prover/bin/server/src/queue.rs @@ -133,13 +133,6 @@ impl Prover { } } -fn encode_batch_header_data(data_hash: &[u8; 32], blob_input: &[u8; 32]) -> [u8; 96] { - let mut batch_header = [0u8; 96]; - batch_header[..32].copy_from_slice(data_hash); - batch_header[32..64].copy_from_slice(blob_input); - batch_header -} - /// Generate ExecutorInput for prover client. async fn gen_client_input( batch_index: u64, @@ -182,9 +175,12 @@ async fn gen_client_input( }; // Save batch_header_ex (uniform for all versions): // | data_hash(32) | blob_input(32) | seqSetVerifyHash(32) | (96 bytes) - let batch_header = encode_batch_header_data(&batch_info.data_hash().0, &blob_input.0); + let mut batch_header: Vec = Vec::with_capacity(96); + batch_header.extend_from_slice(&batch_info.data_hash().0); + batch_header.extend_from_slice(&blob_input.0); + batch_header.extend_from_slice(&batch_info.sequencer_root().0); let mut batch_file = File::create(proof_dir.join("batch_header.data"))?; - batch_file.write_all(&batch_header).expect("failed to batch_header"); + batch_file.write_all(&batch_header[..]).expect("failed to batch_header"); } else { let err = verify_result.unwrap_err(); let error_data = serde_json::json!({ @@ -230,19 +226,3 @@ fn save_trace(batch_index: u64, chunk_traces: &Vec) { serde_json::to_writer_pretty(writer, &chunk_traces).unwrap(); log::info!("chunk_traces of batch_index = {:#?} saved", batch_index); } - -#[cfg(test)] -mod tests { - use super::encode_batch_header_data; - - #[test] - fn batch_header_data_keeps_96_bytes_and_zeroes_the_third_field() { - let data_hash = [0x11; 32]; - let blob_input = [0x22; 32]; - let encoded = encode_batch_header_data(&data_hash, &blob_input); - - assert_eq!(&encoded[..32], &data_hash); - assert_eq!(&encoded[32..64], &blob_input); - assert_eq!(&encoded[64..], &[0u8; 32]); - } -} diff --git a/prover/bin/shadow-prove/abi/Rollup.json b/prover/bin/shadow-prove/abi/Rollup.json index 24828973e..e32ca8619 100644 --- a/prover/bin/shadow-prove/abi/Rollup.json +++ b/prover/bin/shadow-prove/abi/Rollup.json @@ -217,25 +217,6 @@ "name": "RevertBatch", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldAddr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newAddr", - "type": "address" - } - ], - "name": "SubmitterContractUpdated", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -402,25 +383,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -498,9 +460,9 @@ "type": "uint256" }, { - "internalType": "address", - "name": "submitter", - "type": "address" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" } ], "stateMutability": "view", @@ -694,6 +656,28 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "sequencerSets", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", + "type": "tuple" } ], "name": "commitBatch", @@ -745,68 +729,40 @@ "name": "batchDataInput", "type": "tuple" }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ { "components": [ { - "internalType": "uint8", - "name": "version", - "type": "uint8" + "internalType": "uint256", + "name": "signedSequencersBitmap", + "type": "uint256" }, { "internalType": "bytes", - "name": "parentBatchHeader", + "name": "sequencerSets", "type": "bytes" }, { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" + "internalType": "bytes", + "name": "signature", + "type": "bytes" } ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", + "internalType": "struct IRollup.BatchSignatureInput", + "name": "batchSignatureInput", "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" } ], - "name": "commitState", + "name": "commitBatchWithProof", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -924,7 +880,7 @@ "inputs": [ { "internalType": "address", - "name": "_submitterContract", + "name": "_l1StakingContract", "type": "address" }, { @@ -984,19 +940,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newSubmitter", - "type": "address" - } - ], - "name": "initialize4", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -1035,6 +978,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "l1StakingContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1252,19 +1208,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "submitterContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -1379,4 +1322,4 @@ "stateMutability": "payable", "type": "receive" } -] +] \ No newline at end of file diff --git a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json b/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json deleted file mode 100644 index c8c7586c1..000000000 --- a/prover/bin/shadow-prove/abi/pre_submitter/Rollup.json +++ /dev/null @@ -1,1416 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainID", - "type": "uint64" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ErrZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "indexed": true, - "internalType": "string", - "name": "res", - "type": "string" - } - ], - "name": "ChallengeRes", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ChallengeRewardClaim", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - } - ], - "name": "ChallengeState", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "CommitBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "withdrawRoot", - "type": "bytes32" - } - ], - "name": "FinalizeBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ProveRemainingClaimed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "name": "RevertBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "status", - "type": "bool" - } - ], - "name": "UpdateChallenger", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateFinalizationPeriodSeconds", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPercent", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPercent", - "type": "uint256" - } - ], - "name": "UpdateProofRewardPercent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldWindow", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newWindow", - "type": "uint256" - } - ], - "name": "UpdateProofWindow", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPeriod", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPeriod", - "type": "uint256" - } - ], - "name": "UpdateRollupDelayPeriod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newVerifier", - "type": "address" - } - ], - "name": "UpdateVerifier", - "type": "event" - }, - { - "inputs": [], - "name": "LAYER_2_CHAIN_ID", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "__maxNumTxInChunk", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchBlobVersionedHashes", - "outputs": [ - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "batchChallengeReward", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "batchChallenged", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchChallengedSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchDataStore", - "outputs": [ - { - "internalType": "uint256", - "name": "originTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "finalizeTimestamp", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "blockNumber", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchExist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "batchInsideChallengeWindow", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_batchHash", - "type": "bytes32" - } - ], - "name": "challengeState", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "challenges", - "outputs": [ - { - "internalType": "uint64", - "name": "batchIndex", - "type": "uint64" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "challengeDeposit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "challengeSuccess", - "type": "bool" - }, - { - "internalType": "bool", - "name": "finished", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimProveRemaining", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "claimReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitBatch", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "commitBatchWithProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "parentBatchHeader", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "lastBlockNumber", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "numL1Messages", - "type": "uint16" - }, - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "internalType": "struct IRollup.BatchDataInput", - "name": "batchDataInput", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" - } - ], - "name": "commitState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedBatches", - "outputs": [ - { - "internalType": "bytes32", - "name": "batchHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "committedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finalizationPeriodSeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "finalizeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "batchIndex", - "type": "uint256" - } - ], - "name": "finalizedStateRoots", - "outputs": [ - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - } - ], - "name": "importGenesisBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "inChallenge", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1StakingContract", - "type": "address" - }, - { - "internalType": "address", - "name": "_messageQueue", - "type": "address" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_finalizationPeriodSeconds", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofWindow", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_proofRewardPercent", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_prevStateRoot", - "type": "bytes32" - } - ], - "name": "initialize2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rollupDelayPeriod", - "type": "uint256" - } - ], - "name": "initialize3", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "name": "isBatchFinalized", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "challengerAddress", - "type": "address" - } - ], - "name": "isChallenger", - "outputs": [ - { - "internalType": "bool", - "name": "isChallenger", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastCommittedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastFinalizedBatchIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "messageQueue", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofRewardPercent", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofWindow", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveCommittedBatchState", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proveRemaining", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" - } - ], - "name": "proveState", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "removeChallenger", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "revertBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "revertReqIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "rollupDelayPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bool", - "name": "_status", - "type": "bool" - } - ], - "name": "setPause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateFinalizePeriodSeconds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newWindow", - "type": "uint256" - } - ], - "name": "updateProofWindow", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newProofRewardPercent", - "type": "uint256" - } - ], - "name": "updateRewardPercentage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_newPeriod", - "type": "uint256" - } - ], - "name": "updateRollupDelayPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_newVerifier", - "type": "address" - } - ], - "name": "updateVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - } - ], - "name": "withdrawalRoots", - "outputs": [ - { - "internalType": "bool", - "name": "exist", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/prover/bin/shadow-prove/contracts/README.md b/prover/bin/shadow-prove/contracts/README.md index a2e793391..fd66db068 100644 --- a/prover/bin/shadow-prove/contracts/README.md +++ b/prover/bin/shadow-prove/contracts/README.md @@ -16,13 +16,7 @@ forge build EvmVerifier: ``` -forge create --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 src/libs/EvmVerifier.sol:EvmVerifier --constructor-args 0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88 -``` - -For an existing `ShadowRollup`, its owner must switch to the newly deployed verifier before the first proof produced by this program: - -```sh -cast send --rpc-url "$L1_RPC" --private-key "$OWNER_PRIVATE_KEY" "$SHADOW_ROLLUP" "updateVerifier(address)" "$NEW_EVM_VERIFIER" +forge create --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 src/libs/EvmVerifier.sol:EvmVerifier --constructor-args 0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c ``` ShadowRollup diff --git a/prover/bin/shadow-prove/src/abi.rs b/prover/bin/shadow-prove/src/abi.rs index 31c73095a..d98d7b99d 100644 --- a/prover/bin/shadow-prove/src/abi.rs +++ b/prover/bin/shadow-prove/src/abi.rs @@ -1,6 +1,4 @@ -use alloy_primitives::Bytes; -use alloy_sol_types::{sol, SolCall}; -use anyhow::{anyhow, Result}; +use alloy_sol_types::sol; // Codegen from ABI file to interact with the contract. sol!( @@ -9,57 +7,6 @@ sol!( "abi/Rollup.json" ); -// Immutable Rollup ABI from immediately before BatchSignatureInput was removed. -pub mod pre_submitter { - use alloy_sol_types::sol; - - sol!(PreSubmitterRollup, "abi/pre_submitter/Rollup.json"); -} -use pre_submitter::PreSubmitterRollup; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CommitBatchInput { - pub parent_batch_header: Bytes, - pub last_block_number: u64, -} - -/// Derive the target batch's L2 block range from the previous and target commits. -pub fn target_batch_block_range( - previous: &CommitBatchInput, - target: &CommitBatchInput, -) -> (u64, u64) { - (previous.last_block_number + 1, target.last_block_number) -} - -/// A commit carries its parent's header, so the commit after the target is the source of the -/// target batch header. -pub fn target_batch_header_from_next_commit(next: &CommitBatchInput) -> Bytes { - next.parent_batch_header.clone() -} - -/// Decode the pre- or post-upgrade commitBatch calldata handled by shadow-prove. -pub fn decode_commit_batch(data: &[u8]) -> Result { - let selector = - data.get(..4).ok_or_else(|| anyhow!("rollup calldata is shorter than a selector"))?; - - if selector == Rollup::commitBatchCall::SELECTOR { - let call = Rollup::commitBatchCall::abi_decode(data)?; - return Ok(CommitBatchInput { - parent_batch_header: call.batchDataInput.parentBatchHeader, - last_block_number: call.batchDataInput.lastBlockNumber, - }); - } - if selector == PreSubmitterRollup::commitBatchCall::SELECTOR { - let call = PreSubmitterRollup::commitBatchCall::abi_decode(data)?; - return Ok(CommitBatchInput { - parent_batch_header: call.batchDataInput.parentBatchHeader, - last_block_number: call.batchDataInput.lastBlockNumber, - }); - } - - Err(anyhow!("unsupported rollup calldata selector")) -} - sol!( #[sol(rpc)] ShadowRollup, @@ -71,90 +18,3 @@ sol!( SP1Verifier, "abi/SP1Verifier.json" ); - -#[cfg(test)] -mod tests { - use super::*; - use alloy_primitives::{B256, U256}; - - const PRE_SUBMITTER_COMMIT_BATCH: &str = "0x428868b500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000000007111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000301020300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002aabb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ccdd000000000000000000000000000000000000000000000000000000000000"; - const POST_SUBMITTER_COMMIT_BATCH: &str = "0x41f756da0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000003039000000000000000000000000000000000000000000000000000000000000000711111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333300000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"; - - fn calldata(value: &str) -> Vec { - alloy_primitives::hex::decode(value.trim_start_matches("0x")).unwrap() - } - - fn post_submitter_commit_batch(parent_batch_header: &[u8], last_block_number: u64) -> Vec { - Rollup::commitBatchCall { - batchDataInput: IRollup::BatchDataInput { - version: 2, - parentBatchHeader: Bytes::copy_from_slice(parent_batch_header), - lastBlockNumber: last_block_number, - numL1Messages: 0, - prevStateRoot: B256::ZERO, - postStateRoot: B256::ZERO, - withdrawalRoot: B256::ZERO, - }, - } - .abi_encode() - } - - fn pre_submitter_commit_batch(parent_batch_header: &[u8], last_block_number: u64) -> Vec { - PreSubmitterRollup::commitBatchCall { - batchDataInput: pre_submitter::IRollup::BatchDataInput { - version: 2, - parentBatchHeader: Bytes::copy_from_slice(parent_batch_header), - lastBlockNumber: last_block_number, - numL1Messages: 0, - prevStateRoot: B256::ZERO, - postStateRoot: B256::ZERO, - withdrawalRoot: B256::ZERO, - }, - batchSignatureInput: pre_submitter::IRollup::BatchSignatureInput { - signedSequencersBitmap: U256::ZERO, - sequencerSets: Bytes::new(), - signature: Bytes::new(), - }, - } - .abi_encode() - } - - #[test] - fn decodes_fixed_pre_and_post_upgrade_commit_batch_calldata() { - let pre = decode_commit_batch(&calldata(PRE_SUBMITTER_COMMIT_BATCH)).unwrap(); - let post = decode_commit_batch(&calldata(POST_SUBMITTER_COMMIT_BATCH)).unwrap(); - - assert_eq!(pre, post); - assert_eq!(post.last_block_number, 12_345); - assert_eq!(post.parent_batch_header.as_ref(), [1, 2, 3]); - assert_eq!(Rollup::commitBatchCall::SELECTOR, [0x41, 0xf7, 0x56, 0xda]); - assert_eq!(PreSubmitterRollup::commitBatchCall::SELECTOR, [0x42, 0x88, 0x68, 0xb5]); - } - - #[test] - fn rejects_non_commit_batch_calldata() { - assert!(decode_commit_batch(&[]).is_err()); - assert!(decode_commit_batch(&[0xde, 0xad, 0xbe, 0xef]).is_err()); - assert!(decode_commit_batch(&[0x67, 0xca, 0xa3, 0x7a]).is_err()); - assert!(decode_commit_batch(&[0x15, 0x44, 0xba, 0x3a]).is_err()); - assert!(decode_commit_batch(&[0x4e, 0x8f, 0x1d, 0x67]).is_err()); - } - - #[test] - fn decodes_and_assembles_old_new_new_cutover_window() { - let old_calldata = pre_submitter_commit_batch(b"old-parent", 99); - let target_calldata = post_submitter_commit_batch(b"target-parent", 109); - let next_calldata = post_submitter_commit_batch(b"target-header", 119); - assert_eq!(&old_calldata[..4], PreSubmitterRollup::commitBatchCall::SELECTOR); - assert_eq!(&target_calldata[..4], Rollup::commitBatchCall::SELECTOR); - assert_eq!(&next_calldata[..4], Rollup::commitBatchCall::SELECTOR); - - let old = decode_commit_batch(&old_calldata).unwrap(); - let target = decode_commit_batch(&target_calldata).unwrap(); - let next = decode_commit_batch(&next_calldata).unwrap(); - - assert_eq!(target_batch_block_range(&old, &target), (100, 109)); - assert_eq!(target_batch_header_from_next_commit(&next).as_ref(), b"target-header"); - assert_ne!(target.parent_batch_header, target_batch_header_from_next_commit(&next)); - } -} diff --git a/prover/bin/shadow-prove/src/execute.rs b/prover/bin/shadow-prove/src/execute.rs index 4792c1fe0..1a5142e6e 100644 --- a/prover/bin/shadow-prove/src/execute.rs +++ b/prover/bin/shadow-prove/src/execute.rs @@ -252,6 +252,7 @@ mod tests { &inputs, B256::default(), B256::default(), + B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); @@ -267,6 +268,7 @@ mod tests { &inputs, B256::default(), B256::default(), + B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index bbde33794..df1f7292c 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -1,16 +1,11 @@ -use crate::{ - abi::{ - decode_commit_batch, target_batch_block_range, target_batch_header_from_next_commit, - CommitBatchInput, - }, - metrics::METRICS, - BatchInfo, SHADOW_PROVING_BLOCKS_RANGE, -}; +use crate::{metrics::METRICS, BatchInfo, SHADOW_PROVING_BLOCKS_RANGE}; use alloy_consensus::Transaction; use alloy_network::{Network, ReceiptResponse}; use alloy_primitives::{hex, Address, Bytes, Keccak256, TxHash, B256, U256, U64}; use alloy_provider::{DynProvider, Provider}; use alloy_rpc_types::Log; +use alloy_sol_types::SolCall; + use anyhow::{anyhow, Context, Result}; use futures::future::join_all; @@ -19,34 +14,6 @@ use crate::{ ShadowRollup::{self, ShadowRollupInstance}, }; -fn sequencer_set_verify_hash(batch_header: &Bytes) -> Result { - let field: [u8; 32] = batch_header - .get(185..217) - .ok_or_else(|| anyhow!("batch header is shorter than the sequencerSetVerifyHash field"))? - .try_into() - .map_err(|_| anyhow!("invalid sequencerSetVerifyHash field length"))?; - if field != [0u8; 32] { - return Err(anyhow!("sequencerSetVerifyHash must be zero after the upgrade")); - } - Ok(B256::from(field)) -} - -#[cfg(test)] -mod header_field_tests { - use super::*; - - #[test] - fn post_upgrade_header_keeps_the_field_at_185_and_requires_zero() { - let mut header = vec![0x11; 249]; - header[185..217].fill(0); - assert_eq!(sequencer_set_verify_hash(&Bytes::from(header.clone())).unwrap(), B256::ZERO); - - header[216] = 1; - assert!(sequencer_set_verify_hash(&Bytes::from(header)).is_err()); - assert!(sequencer_set_verify_hash(&Bytes::from(vec![0u8; 216])).is_err()); - } -} - #[derive(Clone, Debug)] pub struct BatchSyncer { l1_provider: DynProvider, @@ -170,12 +137,12 @@ where return Err(anyhow!("find commit_batch log error")); } }; - let batch_input = commit_batch_input_inspect(&self.l1_provider, next_tx_hash) + let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) .await .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; log::info!("Found the committed batch, batch index = {:#?}", batch_index_hash.0); - Ok(Some((batch_info, target_batch_header_from_next_commit(&batch_input)))) + Ok(Some((batch_info, batch_input.0))) } /// Fetch a specified batch from l1-rollup by batch_num. @@ -327,12 +294,12 @@ where }; // next(batch_num+1) commitBatch calldata contains curr(batch_num) parentBatchHeader. - let batch_input = commit_batch_input_inspect(&self.l1_provider, next_tx_hash) + let batch_input = batch_input_inspect(&self.l1_provider, next_tx_hash) .await .ok_or_else(|| anyhow!("Failed to inspect batch header"))?; log::info!("Found the specified batch (prev/curr/next): {:?}", batch_index_hash); - Ok(Some((batch_info, target_batch_header_from_next_commit(&batch_input)))) + Ok(Some((batch_info, batch_input.0))) } /** @@ -370,7 +337,6 @@ where // @dev Below is the feilds for `BatchHeader` V1 // * lastBlockNumber 8 uint64 249 The last block number in this batch // ``` - let sequencer_set_verify_hash = sequencer_set_verify_hash(&batch_header)?; let batch_store = ShadowRollup::BatchStore { prevStateRoot: batch_header .get(89..121) @@ -393,7 +359,11 @@ where .unwrap_or_default() .try_into() .unwrap_or_default(), - sequencerSetVerifyHash: sequencer_set_verify_hash, + sequencerSetVerifyHash: batch_header + .get(185..217) + .unwrap_or_default() + .try_into() + .unwrap_or_default(), }; // Commit the shadow batch. @@ -423,12 +393,11 @@ where prev_batch_hash: TxHash, current_batch_hash: TxHash, ) -> Option<((u64, u64), u64)> { - let prev_batch_input = - commit_batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; + let prev_batch_input = batch_input_inspect(&self.l1_provider, prev_batch_hash).await?; let current_batch_input = - commit_batch_input_inspect(&self.l1_provider, current_batch_hash).await?; - let (start_block, end_block) = - target_batch_block_range(&prev_batch_input, ¤t_batch_input); + batch_input_inspect(&self.l1_provider, current_batch_hash).await?; + let start_block = prev_batch_input.1 + 1; + let end_block = current_batch_input.1; if start_block == 0 { log::error!("batch_blocks_inspect: start_block = 0, tx_hash = {:#?}", prev_batch_hash); @@ -490,7 +459,7 @@ where let post_state_root: &[u8] = batch_header.get(121..153).unwrap_or_default(); let withdrawal_root: &[u8] = batch_header.get(153..185).unwrap_or_default(); let data_hash: &[u8] = batch_header.get(25..57).unwrap_or_default(); - let sequencer_set_verify_hash = sequencer_set_verify_hash(batch_header)?; + let sequencer_set_verify_hash: &[u8] = batch_header.get(185..217).unwrap_or_default(); // All versions: blob input at offset 57 (aggregated hash for V2, versioned hash for V0/V1) let blob_input: &[u8] = batch_header.get(57..89).unwrap_or_default(); @@ -511,17 +480,14 @@ where hasher.update(prev_state_root); hasher.update(post_state_root); hasher.update(withdrawal_root); - hasher.update(sequencer_set_verify_hash.as_slice()); + hasher.update(sequencer_set_verify_hash); hasher.update(data_hash); hasher.update(blob_input); Ok(hasher.finalize()) } } -async fn commit_batch_input_inspect( - l1_provider: &DynProvider, - hash: TxHash, -) -> Option { +pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Option<(Bytes, u64)> { //Step1. Get transaction let result = l1_provider.get_transaction_by_hash(hash).await; let tx = match result { @@ -543,18 +509,15 @@ async fn commit_batch_input_inspect( log::warn!("batch inspect: tx.input is empty, tx_hash = {:#?}", hash); return None; } - let input = if let Ok(input) = decode_commit_batch(data) { - input + let param = if let Ok(_param) = Rollup::commitBatchCall::abi_decode(data) { + _param } else { log::error!("batch inspect: decode tx.input error, tx_hash = {:#?}", hash); return None; }; - Some(input) -} - -pub async fn batch_input_inspect(l1_provider: &DynProvider, hash: TxHash) -> Option<(Bytes, u64)> { - let input = commit_batch_input_inspect(l1_provider, hash).await?; - Some((input.parent_batch_header, input.last_block_number)) + let parent_batch_header: Bytes = param.batchDataInput.parentBatchHeader; + let last_block_number: u64 = param.batchDataInput.lastBlockNumber; + Some((parent_batch_header, last_block_number)) } #[tokio::test] async fn test_sync_batch() { diff --git a/prover/contracts/README.md b/prover/contracts/README.md index 40ae7a590..1e97783f6 100644 --- a/prover/contracts/README.md +++ b/prover/contracts/README.md @@ -17,5 +17,5 @@ $ forge test ### Deploy ``` -forge create --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 prover/contracts/src/EvmVerifier.sol:EvmVerifier --constructor-args 0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88 -``` +forge create --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545 prover/contracts/src/EvmVerifier.sol:EvmVerifier --constructor-args 0x00f1b104202c89fe60d973cbf456a4e2e1ec1e7d63c61453b959dda153df798c +``` \ No newline at end of file diff --git a/prover/crates/executor/client/src/lib.rs b/prover/crates/executor/client/src/lib.rs index 285cf1638..7524e1e6f 100644 --- a/prover/crates/executor/client/src/lib.rs +++ b/prover/crates/executor/client/src/lib.rs @@ -31,7 +31,7 @@ pub fn verify(input: ExecutorInput) -> Result { hex::encode(batch_info.withdraw_root().as_slice()), hex::encode(batch_info.data_hash().as_slice()), versioned_hashes.iter().map(|h| hex::encode(h.as_slice())).collect::>(), - hex::encode(B256::ZERO.as_slice()), + hex::encode(batch_info.sequencer_root().as_slice()), input.batch_version, ); let public_input_hash = match input.batch_version { diff --git a/prover/crates/executor/client/src/types/batch.rs b/prover/crates/executor/client/src/types/batch.rs index 9334cfbea..5cb7b7c9a 100644 --- a/prover/crates/executor/client/src/types/batch.rs +++ b/prover/crates/executor/client/src/types/batch.rs @@ -16,6 +16,8 @@ pub struct BatchInfo { pub post_state_root: B256, /// withdraw_root pub withdraw_root: Option, + /// sequencer_root + pub sequencer_root: Option, data_hash: B256, } @@ -25,6 +27,7 @@ impl BatchInfo { block_inputs: &[BlockInput], post_state_root: B256, withdraw_root: B256, + sequencer_root: B256, ) -> Self { let blocks = block_inputs.iter().map(|x| x.current_block.clone()).collect::>(); let chain_id = blocks.first().unwrap().chain_id; @@ -45,6 +48,7 @@ impl BatchInfo { prev_state_root, post_state_root, withdraw_root: Some(withdraw_root), + sequencer_root: Some(sequencer_root), data_hash: l1_data_hash, } } @@ -55,24 +59,20 @@ impl BatchInfo { /// prev state root || /// post state root || /// withdraw root || - /// bytes32(0) || + /// sequencer root || /// txdata hash || /// blob versioned hash /// ) pub fn public_input_hash(&self, versioned_hash: &B256) -> B256 { - self.public_input_hash_with_blob_input(versioned_hash) - } - - fn public_input_hash_with_blob_input(&self, blob_input: &B256) -> B256 { let mut hasher = Keccak256::new(); hasher.update(self.chain_id.to_be_bytes()); hasher.update(self.prev_state_root.as_slice()); hasher.update(self.post_state_root.as_slice()); hasher.update(self.withdraw_root.unwrap().as_slice()); - hasher.update(B256::ZERO.as_slice()); + hasher.update(self.sequencer_root.unwrap().as_slice()); hasher.update(self.data_hash.as_slice()); - hasher.update(blob_input.as_slice()); + hasher.update(versioned_hash.as_slice()); hasher.finalize() } @@ -85,7 +85,15 @@ impl BatchInfo { } let blob_hashes_hash: B256 = blob_hasher.finalize(); - self.public_input_hash_with_blob_input(&blob_hashes_hash) + let mut hasher = Keccak256::new(); + hasher.update(self.chain_id.to_be_bytes()); + hasher.update(self.prev_state_root.as_slice()); + hasher.update(self.post_state_root.as_slice()); + hasher.update(self.withdraw_root.unwrap().as_slice()); + hasher.update(self.sequencer_root.unwrap().as_slice()); + hasher.update(self.data_hash.as_slice()); + hasher.update(blob_hashes_hash.as_slice()); + hasher.finalize() } /// Chain ID of this chunk @@ -100,6 +108,7 @@ impl BatchInfo { prev_state_root: B256::ZERO, post_state_root: B256::ZERO, withdraw_root: Some(B256::ZERO), + sequencer_root: Some(B256::ZERO), data_hash: B256::ZERO, } } @@ -119,6 +128,11 @@ impl BatchInfo { self.withdraw_root.expect("get withdraw_root") } + /// Sequencer root after this chunk + pub fn sequencer_root(&self) -> B256 { + self.sequencer_root.expect("get sequencer_root") + } + /// Data hash of this chunk pub fn data_hash(&self) -> B256 { self.data_hash @@ -139,33 +153,6 @@ mod tests { B256::from(b) } - #[test] - fn public_input_hash_keeps_the_32_byte_field_and_sets_it_to_zero() { - let batch = BatchInfo { - chain_id: TEST_CHAIN_ID, - prev_state_root: make_hash(1), - post_state_root: make_hash(2), - withdraw_root: Some(make_hash(3)), - data_hash: make_hash(4), - }; - let blob_input = make_hash(5); - - let mut preimage = Vec::with_capacity(200); - preimage.extend_from_slice(&TEST_CHAIN_ID.to_be_bytes()); - preimage.extend_from_slice(batch.prev_state_root.as_slice()); - preimage.extend_from_slice(batch.post_state_root.as_slice()); - preimage.extend_from_slice(batch.withdraw_root().as_slice()); - preimage.extend_from_slice(B256::ZERO.as_slice()); - preimage.extend_from_slice(batch.data_hash().as_slice()); - preimage.extend_from_slice(blob_input.as_slice()); - - assert_eq!(preimage.len(), 200); - assert_eq!(batch.public_input_hash(&blob_input), keccak256(&preimage)); - - preimage[104..136].copy_from_slice(make_hash(99).as_slice()); - assert_ne!(batch.public_input_hash(&blob_input), keccak256(&preimage)); - } - /// V2 aggregated hash for a single blob: keccak256(h0) != h0 (not backward-compatible with V1). #[test] fn test_public_input_hash_v2_single_blob_differs_from_v1() { @@ -197,7 +184,7 @@ mod tests { hasher.update(B256::ZERO.as_slice()); // prev_state_root hasher.update(B256::ZERO.as_slice()); // post_state_root hasher.update(B256::ZERO.as_slice()); // withdraw_root - hasher.update(B256::ZERO.as_slice()); // reserved zero field + hasher.update(B256::ZERO.as_slice()); // sequencer_root hasher.update(B256::ZERO.as_slice()); // data_hash hasher.update(aggregated.as_slice()); let expected: B256 = hasher.finalize(); diff --git a/prover/crates/executor/client/src/verifier/evm_verifier.rs b/prover/crates/executor/client/src/verifier/evm_verifier.rs index 946129a52..e35083bc7 100644 --- a/prover/crates/executor/client/src/verifier/evm_verifier.rs +++ b/prover/crates/executor/client/src/verifier/evm_verifier.rs @@ -2,7 +2,9 @@ use crate::types::batch::BatchInfo; use crate::types::error::ClientError; use crate::types::input::BlockInput; use prover_executor_core::MorphExecutor; -use prover_primitives::predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}; +use prover_primitives::predeployed::l2_to_l1_message::{ + SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, +}; use reth_trie::{HashedPostState, KeccakKeyHasher}; use revm::context::BlockEnv; use revm::database::State; @@ -44,16 +46,18 @@ fn execute(mut block_inputs: Vec) -> Result } } - // The withdrawal root is derived from the state of the last verified block. - // The former sequencer-root public-input field is now a fixed zero and does - // not require a dedicated storage witness. + // The post-withdraw-root & post-sequencer-root is required for public inputs. + // Tt is derived from the state of the last verified block. let post_withdraw_root = latest_block.get_storage_value(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT)?; + let post_sequencer_root = + latest_block.get_storage_value(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT)?; Ok(BatchInfo::from_block_inputs( &block_inputs, latest_block.current_block.post_state_root, post_withdraw_root.into(), + post_sequencer_root.into(), )) } diff --git a/prover/crates/executor/host/src/execute.rs b/prover/crates/executor/host/src/execute.rs index b4cb4ba68..10dd2ac31 100644 --- a/prover/crates/executor/host/src/execute.rs +++ b/prover/crates/executor/host/src/execute.rs @@ -3,7 +3,9 @@ use alloy_provider::{DynProvider, Provider}; use anyhow::{bail, Context}; use prover_executor_core::MorphExecutor; use prover_primitives::{ - predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}, + predeployed::l2_to_l1_message::{ + SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, + }, TxTrace, }; use prover_storage_rpc::basic_rpc_db::{BasicRpcDb, RpcDb}; @@ -134,6 +136,14 @@ async fn load_predeployed_contracts( .fetch_storage_at(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT) .await .context("failed to fetch WITHDRAW_ROOT_ADDRESS storage slot")?; + rpc_db + .fetch_account_info(SEQUENCER_ROOT_ADDRESS) + .await + .context("failed to fetch SEQUENCER_ROOT_ADDRESS account info")?; + rpc_db + .fetch_storage_at(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT) + .await + .context("failed to fetch SEQUENCER_ROOT_ADDRESS storage slot")?; Ok(()) } diff --git a/prover/crates/primitives/src/predeployed.rs b/prover/crates/primitives/src/predeployed.rs index dd5800071..fe42ed8c6 100644 --- a/prover/crates/primitives/src/predeployed.rs +++ b/prover/crates/primitives/src/predeployed.rs @@ -37,4 +37,10 @@ pub mod l2_to_l1_message { address!("0x5300000000000000000000000000000000000001"); /// Withdraw root slot pub const WITHDRAW_ROOT_SLOT: U256 = uint!(33_U256); + + /// Sequencer root address + pub const SEQUENCER_ROOT_ADDRESS: Address = + address!("0x5300000000000000000000000000000000000017"); + /// Sequencer root slot + pub const SEQUENCER_ROOT_SLOT: U256 = uint!(101_U256); } From 81b4d38bc427651ba858b0099254a12ab60120b5 Mon Sep 17 00:00:00 2001 From: kathy <22675649+anylots@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:55:38 +0800 Subject: [PATCH 34/38] Modify prover and gas-oracle to accommodate centralization-cleanup. --- gas-oracle/app/src/abi/Rollup.json | 269 +++- prover/bin/challenge/src/abi/Rollup.json | 269 +++- prover/bin/challenge/src/handler.rs | 4 +- prover/bin/server/src/queue.rs | 1 - prover/bin/shadow-prove/abi/Rollup.json | 177 ++- prover/bin/shadow-prove/abi/ShadowRollup.json | 1326 ++++++++--------- .../contracts/bytecode/ShadowRollup.json | 1326 ++++++++--------- .../contracts/src/ShadowRollup.sol | 14 +- prover/bin/shadow-prove/src/execute.rs | 2 - prover/bin/shadow-prove/src/shadow_rollup.rs | 24 +- prover/crates/executor/client/src/lib.rs | 3 +- .../crates/executor/client/src/types/batch.rs | 15 +- .../client/src/verifier/evm_verifier.rs | 7 +- prover/crates/executor/host/src/execute.rs | 12 +- prover/crates/primitives/src/predeployed.rs | 6 - 15 files changed, 1922 insertions(+), 1533 deletions(-) diff --git a/gas-oracle/app/src/abi/Rollup.json b/gas-oracle/app/src/abi/Rollup.json index 28f7a5c6d..24828973e 100644 --- a/gas-oracle/app/src/abi/Rollup.json +++ b/gas-oracle/app/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -968,6 +1126,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1226,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1317,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/prover/bin/challenge/src/abi/Rollup.json b/prover/bin/challenge/src/abi/Rollup.json index 28f7a5c6d..24828973e 100644 --- a/prover/bin/challenge/src/abi/Rollup.json +++ b/prover/bin/challenge/src/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -306,6 +325,25 @@ "name": "UpdateProofWindow", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPeriod", + "type": "uint256" + } + ], + "name": "UpdateRollupDelayPeriod", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -364,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -441,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -637,33 +694,121 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, + } + ], + "name": "commitBatch", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + } + ], + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "version", + "type": "uint8" + }, { "internalType": "bytes", - "name": "signature", + "name": "parentBatchHeader", "type": "bytes" + }, + { + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" } ], - "name": "commitBatch", + "name": "commitState", "outputs": [], - "stateMutability": "payable", + "stateMutability": "nonpayable", "type": "function" }, { @@ -779,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -826,6 +971,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rollupDelayPeriod", + "type": "uint256" + } + ], + "name": "initialize3", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -864,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -968,6 +1126,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "proveCommittedBatchState", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "proveRemaining", @@ -1050,6 +1226,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "rollupDelayPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1063,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1115,6 +1317,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newPeriod", + "type": "uint256" + } + ], + "name": "updateRollupDelayPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/prover/bin/challenge/src/handler.rs b/prover/bin/challenge/src/handler.rs index 36eac035f..94eb36cce 100644 --- a/prover/bin/challenge/src/handler.rs +++ b/prover/bin/challenge/src/handler.rs @@ -417,7 +417,6 @@ struct BatchInfo { prev_state_root: [u8; 32], post_state_root: [u8; 32], withdrawal_root: [u8; 32], - sequencer_set_verify_hash: [u8; 32], parent_batch_hash: [u8; 32], } @@ -490,7 +489,6 @@ impl BatchInfo { log::debug!("batch_header_ex len: {:#?}", batch_header_ex.len()); self.data_hash = batch_header_ex.get(0..32).unwrap_or_default().try_into().unwrap_or_default(); - self.sequencer_set_verify_hash = batch_header_ex.get(64..96).unwrap_or_default().try_into().unwrap_or_default(); // All versions: single hash at [32..64] (aggregated for V2, versioned for V0/V1) let hash: [u8; 32] = batch_header_ex.get(32..64).unwrap_or_default().try_into().unwrap_or_default(); @@ -510,7 +508,7 @@ impl BatchInfo { batch_header.extend_from_slice(&self.prev_state_root); batch_header.extend_from_slice(&self.post_state_root); batch_header.extend_from_slice(&self.withdrawal_root); - batch_header.extend_from_slice(&self.sequencer_set_verify_hash); + batch_header.extend_from_slice(&[0u8; 32]); batch_header.extend_from_slice(&self.parent_batch_hash); batch_header.extend_from_slice(&self.end_block.to_be_bytes()); Bytes::from(batch_header) diff --git a/prover/bin/server/src/queue.rs b/prover/bin/server/src/queue.rs index 219a50e69..37306e489 100644 --- a/prover/bin/server/src/queue.rs +++ b/prover/bin/server/src/queue.rs @@ -178,7 +178,6 @@ async fn gen_client_input( let mut batch_header: Vec = Vec::with_capacity(96); batch_header.extend_from_slice(&batch_info.data_hash().0); batch_header.extend_from_slice(&blob_input.0); - batch_header.extend_from_slice(&batch_info.sequencer_root().0); let mut batch_file = File::create(proof_dir.join("batch_header.data"))?; batch_file.write_all(&batch_header[..]).expect("failed to batch_header"); } else { diff --git a/prover/bin/shadow-prove/abi/Rollup.json b/prover/bin/shadow-prove/abi/Rollup.json index e32ca8619..24828973e 100644 --- a/prover/bin/shadow-prove/abi/Rollup.json +++ b/prover/bin/shadow-prove/abi/Rollup.json @@ -217,6 +217,25 @@ "name": "RevertBatch", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldAddr", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newAddr", + "type": "address" + } + ], + "name": "SubmitterContractUpdated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -383,6 +402,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "batchIndex", + "type": "uint256" + } + ], + "name": "batchBlobVersionedHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -460,9 +498,9 @@ "type": "uint256" }, { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "address", + "name": "submitter", + "type": "address" } ], "stateMutability": "view", @@ -656,28 +694,6 @@ "internalType": "struct IRollup.BatchDataInput", "name": "batchDataInput", "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "sequencerSets", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", - "type": "tuple" } ], "name": "commitBatch", @@ -729,40 +745,68 @@ "name": "batchDataInput", "type": "tuple" }, + { + "internalType": "bytes", + "name": "_batchHeader", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_batchProof", + "type": "bytes" + } + ], + "name": "commitBatchWithProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "components": [ { - "internalType": "uint256", - "name": "signedSequencersBitmap", - "type": "uint256" + "internalType": "uint8", + "name": "version", + "type": "uint8" }, { "internalType": "bytes", - "name": "sequencerSets", + "name": "parentBatchHeader", "type": "bytes" }, { - "internalType": "bytes", - "name": "signature", - "type": "bytes" + "internalType": "uint64", + "name": "lastBlockNumber", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "numL1Messages", + "type": "uint16" + }, + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" } ], - "internalType": "struct IRollup.BatchSignatureInput", - "name": "batchSignatureInput", + "internalType": "struct IRollup.BatchDataInput", + "name": "batchDataInput", "type": "tuple" - }, - { - "internalType": "bytes", - "name": "_batchHeader", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "_batchProof", - "type": "bytes" } ], - "name": "commitBatchWithProof", + "name": "commitState", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -880,7 +924,7 @@ "inputs": [ { "internalType": "address", - "name": "_l1StakingContract", + "name": "_submitterContract", "type": "address" }, { @@ -940,6 +984,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newSubmitter", + "type": "address" + } + ], + "name": "initialize4", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -978,19 +1035,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "l1StakingContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "lastCommittedBatchIndex", @@ -1208,6 +1252,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "submitterContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -1322,4 +1379,4 @@ "stateMutability": "payable", "type": "receive" } -] \ No newline at end of file +] diff --git a/prover/bin/shadow-prove/abi/ShadowRollup.json b/prover/bin/shadow-prove/abi/ShadowRollup.json index 0c6177dc5..0a1036a75 100644 --- a/prover/bin/shadow-prove/abi/ShadowRollup.json +++ b/prover/bin/shadow-prove/abi/ShadowRollup.json @@ -1,675 +1,655 @@ { - "abi": [ - { - "type": "constructor", - "inputs": [ - { - "name": "_chainId", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_verifier", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "commitBatch", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_batchData", - "type": "tuple", - "internalType": "struct ShadowRollup.BatchStore", - "components": [ - { - "name": "prevStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "postStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "withdrawalRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "dataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "blobVersionedHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "sequencerSetVerifyHash", - "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "committedBatchStores", - "inputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "prevStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "postStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "withdrawalRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "dataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "blobVersionedHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "sequencerSetVerifyHash", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isProveSuccess", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "layer2ChainId", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint64", - "internalType": "uint64" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "owner", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "proveState", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_proof", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proveStatus", - "inputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "renounceOwnership", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferOwnership", - "inputs": [ - { - "name": "newOwner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "updateVerifier", - "inputs": [ - { - "name": "_verifier", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "verifier", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "OwnershipTransferred", - "inputs": [ - { - "name": "previousOwner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "newOwner", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - } - ], - "bytecode": { - "object": "0x60a060405234801561001057600080fd5b5060405161091138038061091183398101604081905261002f916100bb565b6100383361006b565b6001600160401b0391909116608052600180546001600160a01b0319166001600160a01b0390921691909117905561010d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100ce57600080fd5b82516001600160401b03811681146100e557600080fd5b60208401519092506001600160a01b038116811461010257600080fd5b809150509250929050565b6080516107e361012e6000396000818160b3015261032201526107e36000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101c85780638da5cb5b146101d057806397fc007c146101e15780639d049dda146101f4578063e7047c0414610207578063f2fde38b1461022a57600080fd5b806303c7f4af146100ae5780630b79cdda146100f357806325684280146101655780632b7ac3f31461018857806359ef1120146101b3575b600080fd5b6100d57f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610138610101366004610607565b6002602081905260009182526040909120805460018201549282015460038301546004840154600590940154929493919290919086565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016100ea565b610178610173366004610607565b61023d565b60405190151581526020016100ea565b60015461019b906001600160a01b031681565b6040516001600160a01b0390911681526020016100ea565b6101c66101c136600461063d565b61029e565b005b6101c661043e565b6000546001600160a01b031661019b565b6101c66101ef3660046106c0565b610452565b6101c66102023660046106f0565b61047c565b610178610215366004610607565b60036020526000908152604090205460ff1681565b6101c66102383660046106c0565b6104e4565b60008082116102885760405162461bcd60e51b81526020600482015260126024820152710d2dcecc2d8d2c840c4c2e8c6d092dcc8caf60731b60448201526064015b60405180910390fd5b5060009081526003602052604090205460ff1690565b806102de5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103d3590383937b7b360811b604482015260640161027f565b67ffffffffffffffff8316600090815260026020818152604080842080546001820154948201546005830154600384015460049094015494516001600160c01b03197f000000000000000000000000000000000000000000000000000000000000000060c01b1696810196909652602886019290925260488501959095526068840194909452608883019390935260a882019290925260c881019190915260e80160408051808303601f19018152828252805160209182012060015491840181905293506001600160a01b03169163b768f1c99186918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016103e49392919061072f565b60006040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b50505067ffffffffffffffff9094166000908152600360205260409020805460ff1916600117905550505050565b61044661055d565b61045060006105b7565b565b61045a61055d565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61048461055d565b67ffffffffffffffff8216600090815260026020526040902081906104de8282813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a082013560058201555050565b50505050565b6104ec61055d565b6001600160a01b0381166105515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161027f565b61055a816105b7565b50565b6000546001600160a01b031633146104505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161027f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561061957600080fd5b5035919050565b803567ffffffffffffffff8116811461063857600080fd5b919050565b60008060006040848603121561065257600080fd5b61065b84610620565b9250602084013567ffffffffffffffff8082111561067857600080fd5b818601915086601f83011261068c57600080fd5b81358181111561069b57600080fd5b8760208285010111156106ad57600080fd5b6020830194508093505050509250925092565b6000602082840312156106d257600080fd5b81356001600160a01b03811681146106e957600080fd5b9392505050565b60008082840360e081121561070457600080fd5b61070d84610620565b925060c0601f198201121561072157600080fd5b506020830190509250929050565b60408152826040820152828460608301376000606084830101526000601f1980601f860116830160206060858303016020860152855180606084015260005b8181101561078a5787810183015184820160800152820161076e565b50600060808285010152608084601f83011684010194505050505094935050505056fea2646970667358221220f1cf592fa16f148c60584b254200a54483c2809be910a3ee9581d0c69de4d9de64736f6c63430008180033", - "sourceMap": "219:2419:25:-:0;;;878:119;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;929:32:24;734:10:23;929:18:24;:32::i;:::-;-1:-1:-1;;;;;936:24:25;;;;;;970:8;:20;;-1:-1:-1;;;;;;970:20:25;-1:-1:-1;;;;;970:20:25;;;;;;;;;219:2419;;2419:187:24;2492:16;2511:6;;-1:-1:-1;;;;;2527:17:24;;;-1:-1:-1;;;;;;2527:17:24;;;;;;2559:40;;2511:6;;;;;;;2559:40;;2492:16;2559:40;2482:124;2419:187;:::o;14:463:31:-;92:6;100;153:2;141:9;132:7;128:23;124:32;121:52;;;169:1;166;159:12;121:52;195:16;;-1:-1:-1;;;;;240:30:31;;230:41;;220:69;;285:1;282;275:12;220:69;358:2;343:18;;337:25;308:5;;-1:-1:-1;;;;;;393:33:31;;381:46;;371:74;;441:1;438;431:12;371:74;464:7;454:17;;;14:463;;;;;:::o;:::-;219:2419:25;;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101c85780638da5cb5b146101d057806397fc007c146101e15780639d049dda146101f4578063e7047c0414610207578063f2fde38b1461022a57600080fd5b806303c7f4af146100ae5780630b79cdda146100f357806325684280146101655780632b7ac3f31461018857806359ef1120146101b3575b600080fd5b6100d57f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610138610101366004610607565b6002602081905260009182526040909120805460018201549282015460038301546004840154600590940154929493919290919086565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016100ea565b610178610173366004610607565b61023d565b60405190151581526020016100ea565b60015461019b906001600160a01b031681565b6040516001600160a01b0390911681526020016100ea565b6101c66101c136600461063d565b61029e565b005b6101c661043e565b6000546001600160a01b031661019b565b6101c66101ef3660046106c0565b610452565b6101c66102023660046106f0565b61047c565b610178610215366004610607565b60036020526000908152604090205460ff1681565b6101c66102383660046106c0565b6104e4565b60008082116102885760405162461bcd60e51b81526020600482015260126024820152710d2dcecc2d8d2c840c4c2e8c6d092dcc8caf60731b60448201526064015b60405180910390fd5b5060009081526003602052604090205460ff1690565b806102de5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103d3590383937b7b360811b604482015260640161027f565b67ffffffffffffffff8316600090815260026020818152604080842080546001820154948201546005830154600384015460049094015494516001600160c01b03197f000000000000000000000000000000000000000000000000000000000000000060c01b1696810196909652602886019290925260488501959095526068840194909452608883019390935260a882019290925260c881019190915260e80160408051808303601f19018152828252805160209182012060015491840181905293506001600160a01b03169163b768f1c99186918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016103e49392919061072f565b60006040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b50505067ffffffffffffffff9094166000908152600360205260409020805460ff1916600117905550505050565b61044661055d565b61045060006105b7565b565b61045a61055d565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61048461055d565b67ffffffffffffffff8216600090815260026020526040902081906104de8282813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a082013560058201555050565b50505050565b6104ec61055d565b6001600160a01b0381166105515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161027f565b61055a816105b7565b50565b6000546001600160a01b031633146104505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161027f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561061957600080fd5b5035919050565b803567ffffffffffffffff8116811461063857600080fd5b919050565b60008060006040848603121561065257600080fd5b61065b84610620565b9250602084013567ffffffffffffffff8082111561067857600080fd5b818601915086601f83011261068c57600080fd5b81358181111561069b57600080fd5b8760208285010111156106ad57600080fd5b6020830194508093505050509250925092565b6000602082840312156106d257600080fd5b81356001600160a01b03811681146106e957600080fd5b9392505050565b60008082840360e081121561070457600080fd5b61070d84610620565b925060c0601f198201121561072157600080fd5b506020830190509250929050565b60408152826040820152828460608301376000606084830101526000601f1980601f860116830160206060858303016020860152855180606084015260005b8181101561078a5787810183015184820160800152820161076e565b50600060808285010152608084601f83011684010194505050505094935050505056fea2646970667358221220f1cf592fa16f148c60584b254200a54483c2809be910a3ee9581d0c69de4d9de64736f6c63430008180033", - "sourceMap": "219:2419:25:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;324:37;;;;;;;;188:18:31;176:31;;;158:50;;146:2;131:18;324:37:25;;;;;;;;670:58;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;691:25:31;;;747:2;732:18;;725:34;;;;775:18;;;768:34;;;;833:2;818:18;;811:34;876:3;861:19;;854:35;920:3;905:19;;898:35;678:3;663:19;670:58:25;404:535:31;2458:178:25;;;;;;:::i;:::-;;:::i;:::-;;;1109:14:31;;1102:22;1084:41;;1072:2;1057:18;2458:178:25;944:187:31;414:23:25;;;;;-1:-1:-1;;;;;414:23:25;;;;;;-1:-1:-1;;;;;1300:32:31;;;1282:51;;1270:2;1255:18;414:23:25;1136:203:31;1396:897:25;;;;;;:::i;:::-;;:::i;:::-;;1817:101:24;;;:::i;1194:85::-;1240:7;1266:6;-1:-1:-1;;;;;1266:6:24;1194:85;;2353:99:25;;;;;;:::i;:::-;;:::i;1157:177::-;;;;;;:::i;:::-;;:::i;763:43::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2067:198:24;;;;;;:::i;:::-;;:::i;2458:178:25:-;2526:4;2564:1;2550:11;:15;2542:46;;;;-1:-1:-1;;;2542:46:25;;3032:2:31;2542:46:25;;;3014:21:31;3071:2;3051:18;;;3044:30;-1:-1:-1;;;3090:18:31;;;3083:48;3148:18;;2542:46:25;;;;;;;;;-1:-1:-1;2605:24:25;;;;:11;:24;;;;;;;;;2458:178::o;1396:897::-;1521:17;1513:46;;;;-1:-1:-1;;;1513:46:25;;3379:2:31;1513:46:25;;;3361:21:31;3418:2;3398:18;;;3391:30;-1:-1:-1;;;3437:18:31;;;3430:46;3493:18;;1513:46:25;3177:340:31;1513:46:25;1685:33;;;1570:24;1685:33;;;:20;:33;;;;;;;;:47;;1750;;;;1815:48;;;;1881:56;;;;1955:42;;;;2015:51;;;;;1620:460;;-1:-1:-1;;;;;;1654:13:25;3855:3:31;3833:16;3829:51;1620:460:25;;;3817:64:31;;;;3897:11;;;3890:27;;;;3933:12;;;3926:28;;;;3970:12;;;3963:28;;;;4007:13;;;4000:29;;;;4045:13;;;4038:29;;;;4083:13;;;4076:29;;;;4121:13;;1620:460:25;;;;;;-1:-1:-1;;1620:460:25;;;;;;1597:493;;1620:460;1597:493;;;;2140:8;;2200:34;;;4274:19:31;;;1597:493:25;-1:-1:-1;;;;;;2140:8:25;;2128:38;;2180:6;;;;4309:12:31;2200:34:25;;;;;;;;;;;;2128:116;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2255:24:25;;;;;;;;:11;:24;;;;;:31;;-1:-1:-1;;2255:31:25;2282:4;2255:31;;;-1:-1:-1;;;;1396:897:25:o;1817:101:24:-;1087:13;:11;:13::i;:::-;1881:30:::1;1908:1;1881:18;:30::i;:::-;1817:101::o:0;2353:99:25:-;1087:13:24;:11;:13::i;:::-;2425:8:25::1;:20:::0;;-1:-1:-1;;;;;;2425:20:25::1;-1:-1:-1::0;;;;;2425:20:25;;;::::1;::::0;;;::::1;::::0;;2353:99::o;1157:177::-;1087:13:24;:11;:13::i;:::-;1281:33:25::1;::::0;::::1;;::::0;;;:20:::1;:33;::::0;;;;1317:10;;1281:46:::1;1317:10:::0;1281:33;5384:5:31;5371:19;5365:4;5358:33;5445:2;5438:5;5434:14;5421:28;5417:1;5411:4;5407:12;5400:50;5504:2;5497:5;5493:14;5480:28;5476:1;5470:4;5466:12;5459:50;5563:2;5556:5;5552:14;5539:28;5535:1;5529:4;5525:12;5518:50;5622:3;5615:5;5611:15;5598:29;5594:1;5588:4;5584:12;5577:51;5682:3;5675:5;5671:15;5658:29;5654:1;5648:4;5644:12;5637:51;;;5213:481;1281:46:25::1;-1:-1:-1::0;;;;1157:177:25:o;2067:198:24:-;1087:13;:11;:13::i;:::-;-1:-1:-1;;;;;2155:22:24;::::1;2147:73;;;::::0;-1:-1:-1;;;2147:73:24;;5901:2:31;2147:73:24::1;::::0;::::1;5883:21:31::0;5940:2;5920:18;;;5913:30;5979:34;5959:18;;;5952:62;-1:-1:-1;;;6030:18:31;;;6023:36;6076:19;;2147:73:24::1;5699:402:31::0;2147:73:24::1;2230:28;2249:8;2230:18;:28::i;:::-;2067:198:::0;:::o;1352:130::-;1240:7;1266:6;-1:-1:-1;;;;;1266:6:24;734:10:23;1415:23:24;1407:68;;;;-1:-1:-1;;;1407:68:24;;6308:2:31;1407:68:24;;;6290:21:31;;;6327:18;;;6320:30;6386:34;6366:18;;;6359:62;6438:18;;1407:68:24;6106:356:31;2419:187:24;2492:16;2511:6;;-1:-1:-1;;;;;2527:17:24;;;-1:-1:-1;;;;;;2527:17:24;;;;;;2559:40;;2511:6;;;;;;;2559:40;;2492:16;2559:40;2482:124;2419:187;:::o;219:180:31:-;278:6;331:2;319:9;310:7;306:23;302:32;299:52;;;347:1;344;337:12;299:52;-1:-1:-1;370:23:31;;219:180;-1:-1:-1;219:180:31:o;1344:171::-;1411:20;;1471:18;1460:30;;1450:41;;1440:69;;1505:1;1502;1495:12;1440:69;1344:171;;;:::o;1520:663::-;1598:6;1606;1614;1667:2;1655:9;1646:7;1642:23;1638:32;1635:52;;;1683:1;1680;1673:12;1635:52;1706:28;1724:9;1706:28;:::i;:::-;1696:38;;1785:2;1774:9;1770:18;1757:32;1808:18;1849:2;1841:6;1838:14;1835:34;;;1865:1;1862;1855:12;1835:34;1903:6;1892:9;1888:22;1878:32;;1948:7;1941:4;1937:2;1933:13;1929:27;1919:55;;1970:1;1967;1960:12;1919:55;2010:2;1997:16;2036:2;2028:6;2025:14;2022:34;;;2052:1;2049;2042:12;2022:34;2097:7;2092:2;2083:6;2079:2;2075:15;2071:24;2068:37;2065:57;;;2118:1;2115;2108:12;2065:57;2149:2;2145;2141:11;2131:21;;2171:6;2161:16;;;;;1520:663;;;;;:::o;2188:286::-;2247:6;2300:2;2288:9;2279:7;2275:23;2271:32;2268:52;;;2316:1;2313;2306:12;2268:52;2342:23;;-1:-1:-1;;;;;2394:31:31;;2384:42;;2374:70;;2440:1;2437;2430:12;2374:70;2463:5;2188:286;-1:-1:-1;;;2188:286:31:o;2479:346::-;2577:6;2585;2629:9;2620:7;2616:23;2659:3;2655:2;2651:12;2648:32;;;2676:1;2673;2666:12;2648:32;2699:28;2717:9;2699:28;:::i;:::-;2689:38;-1:-1:-1;2761:3:31;-1:-1:-1;;2743:16:31;;2739:26;2736:46;;;2778:1;2775;2768:12;2736:46;;2816:2;2805:9;2801:18;2791:28;;2479:346;;;;;:::o;4332:876::-;4535:2;4524:9;4517:21;4574:6;4569:2;4558:9;4554:18;4547:34;4631:6;4623;4618:2;4607:9;4603:18;4590:48;4687:1;4682:2;4673:6;4662:9;4658:22;4654:31;4647:42;4498:4;4712:2;4708:7;4770:2;4765;4757:6;4753:15;4749:24;4738:9;4734:40;4793:4;4859:2;4847:9;4843:2;4839:18;4835:27;4828:4;4817:9;4813:20;4806:57;4892:6;4886:13;4928:6;4923:2;4919;4915:11;4908:27;4953:1;4963:134;4977:6;4974:1;4971:13;4963:134;;;5066:14;;;5062:23;;5056:30;5038:10;;;5050:3;5034:20;5027:60;4992:10;;4963:134;;;4967:3;5140:1;5134:3;5125:6;5121:2;5117:15;5113:25;5106:36;5198:3;5192:2;5187;5179:6;5175:15;5171:24;5167:2;5163:33;5159:43;5151:51;;;;;;4332:876;;;;;;:::o", - "linkReferences": {}, - "immutableReferences": { - "40031": [ - { - "start": 179, - "length": 32 - }, - { - "start": 802, - "length": 32 - } - ] - } - }, - "methodIdentifiers": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": "9d049dda", - "committedBatchStores(uint256)": "0b79cdda", - "isProveSuccess(uint256)": "25684280", - "layer2ChainId()": "03c7f4af", - "owner()": "8da5cb5b", - "proveState(uint64,bytes)": "59ef1120", - "proveStatus(uint256)": "e7047c04", - "renounceOwnership()": "715018a6", - "transferOwnership(address)": "f2fde38b", - "updateVerifier(address)": "97fc007c", - "verifier()": "2b7ac3f3" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sequencerSetVerifyHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ShadowRollup.BatchStore\",\"name\":\"_batchData\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatchStores\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sequencerSetVerifyHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isProveSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"proveStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"params\":{\"_batchData\":\"The batch data\",\"_batchIndex\":\"The index of batch\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ShadowRollup\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"notice\":\"Commit a batch of transactions on layer 1.\"},\"layer2ChainId()\":{\"notice\":\"The chain id of the corresponding layer 2 chain.\"},\"updateVerifier(address)\":{\"notice\":\"Update the address verifier contract.\"},\"verifier()\":{\"notice\":\"The address of zkvm verifier.\"}},\"notice\":\"This contract maintains data for shadow rollup.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ShadowRollup.sol\":\"ShadowRollup\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/Context.sol\":{\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c\",\"dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h\"]},\"src/Ownable.sol\":{\"keccak256\":\"0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a\",\"dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB\"]},\"src/ShadowRollup.sol\":{\"keccak256\":\"0x7f2b4137ac3d0247c894349f6a3c43397a85e4fc46a52d527ef423f6952ffda9\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1a6e967d36f0f7b0a4c61c441314f19486f8f1288c2f61d1e2aa113001f8647a\",\"dweb:/ipfs/QmY2pZQAKL2QRDW746pmbvHegfLkYtbiShpXcqWNvXKARd\"]},\"src/libs/EvmVerifier.sol\":{\"keccak256\":\"0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2\",\"dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR\"]},\"src/libs/ISP1Verifier.sol\":{\"keccak256\":\"0xa2b12c98dab270cd8cf31437ed098fac584f46402c4a8a6abc4916762cf2f25a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://afaf82202de8cfa5931655d64736cb60f3fe4ea7e8de3f7783c8b7b5f64279a0\",\"dweb:/ipfs/QmSd2jcaJ3EZFLZyomhsDZVZqCeQaWWAwi5EUsE4fznB7d\"]},\"src/libs/PlonkVerifier.sol\":{\"keccak256\":\"0xd48c175491e3e69523ab78edce43662c44e6b3149b6aaca8689b5f11f1dbc7e4\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://d487e6c4270fd354d76217e50d979379cb3a19c31415a6af9fac63e8de06ef7e\",\"dweb:/ipfs/Qmcrr1pkQc6aoUGoX5sKoeQeXUH9b1T1p2Xyd3ZJUot4iX\"]},\"src/libs/SP1VerifierPlonk.sol\":{\"keccak256\":\"0xce6301ea7c14ca3756bb845316e4e25267ce3004f330f0b47e4ac07a39a0ab76\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://15cc4090f17e9d37478c4b49367d0b6fa466a3169c5431fc0aff76ba0a5f86f3\",\"dweb:/ipfs/QmWH1z6p2yeExs9yVA2p1b9X4WjFy3R9KJHKNghn7rmsWp\"]}},\"version\":1}", - "metadata": { - "compiler": { - "version": "0.8.24+commit.e11b9ed9" - }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainId", - "type": "uint64" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "previousOwner", - "type": "address", - "indexed": true - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address", - "indexed": true - } - ], - "type": "event", - "name": "OwnershipTransferred", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_batchIndex", - "type": "uint64" - }, - { - "internalType": "struct ShadowRollup.BatchStore", - "name": "_batchData", - "type": "tuple", - "components": [ - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "sequencerSetVerifyHash", - "type": "bytes32" - } - ] - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "commitBatch" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "committedBatchStores", - "outputs": [ - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "sequencerSetVerifyHash", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "isProveSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "layer2ChainId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "_proof", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "proveState" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "proveStatus", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "function", - "name": "renounceOwnership" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "transferOwnership" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_verifier", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "updateVerifier" - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": { - "params": { - "_batchData": "The batch data", - "_batchIndex": "The index of batch" - } - }, - "owner()": { - "details": "Returns the address of the current owner." - }, - "renounceOwnership()": { - "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." - }, - "transferOwnership(address)": { - "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": { - "notice": "Commit a batch of transactions on layer 1." - }, - "layer2ChainId()": { - "notice": "The chain id of the corresponding layer 2 chain." - }, - "updateVerifier(address)": { - "notice": "Update the address verifier contract." - }, - "verifier()": { - "notice": "The address of zkvm verifier." - } - }, - "version": 1 - } - }, - "settings": { - "remappings": [ - "forge-std/=lib/forge-std/src/" - ], - "optimizer": { - "enabled": true, - "runs": 200 - }, - "metadata": { - "bytecodeHash": "ipfs" - }, - "compilationTarget": { - "src/ShadowRollup.sol": "ShadowRollup" - }, - "evmVersion": "paris", - "libraries": {} - }, - "sources": { - "src/Context.sol": { - "keccak256": "0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439", - "urls": [ - "bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c", - "dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h" - ], - "license": "MIT" - }, - "src/Ownable.sol": { - "keccak256": "0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8", - "urls": [ - "bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a", - "dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB" - ], - "license": "MIT" - }, - "src/ShadowRollup.sol": { - "keccak256": "0x7f2b4137ac3d0247c894349f6a3c43397a85e4fc46a52d527ef423f6952ffda9", - "urls": [ - "bzz-raw://1a6e967d36f0f7b0a4c61c441314f19486f8f1288c2f61d1e2aa113001f8647a", - "dweb:/ipfs/QmY2pZQAKL2QRDW746pmbvHegfLkYtbiShpXcqWNvXKARd" - ], - "license": "MIT" - }, - "src/libs/EvmVerifier.sol": { - "keccak256": "0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb", - "urls": [ - "bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2", - "dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR" - ], - "license": "MIT" - }, - "src/libs/ISP1Verifier.sol": { - "keccak256": "0xa2b12c98dab270cd8cf31437ed098fac584f46402c4a8a6abc4916762cf2f25a", - "urls": [ - "bzz-raw://afaf82202de8cfa5931655d64736cb60f3fe4ea7e8de3f7783c8b7b5f64279a0", - "dweb:/ipfs/QmSd2jcaJ3EZFLZyomhsDZVZqCeQaWWAwi5EUsE4fznB7d" - ], - "license": "MIT" - }, - "src/libs/PlonkVerifier.sol": { - "keccak256": "0xd48c175491e3e69523ab78edce43662c44e6b3149b6aaca8689b5f11f1dbc7e4", - "urls": [ - "bzz-raw://d487e6c4270fd354d76217e50d979379cb3a19c31415a6af9fac63e8de06ef7e", - "dweb:/ipfs/Qmcrr1pkQc6aoUGoX5sKoeQeXUH9b1T1p2Xyd3ZJUot4iX" - ], - "license": "Apache-2.0" - }, - "src/libs/SP1VerifierPlonk.sol": { - "keccak256": "0xce6301ea7c14ca3756bb845316e4e25267ce3004f330f0b47e4ac07a39a0ab76", - "urls": [ - "bzz-raw://15cc4090f17e9d37478c4b49367d0b6fa466a3169c5431fc0aff76ba0a5f86f3", - "dweb:/ipfs/QmWH1z6p2yeExs9yVA2p1b9X4WjFy3R9KJHKNghn7rmsWp" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "id": 25 + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "_chainId", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_verifier", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "commitBatch", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_batchData", + "type": "tuple", + "internalType": "struct ShadowRollup.BatchStore", + "components": [ + { + "name": "prevStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "postStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "withdrawalRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "blobVersionedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "committedBatchStores", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "prevStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "postStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "withdrawalRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "blobVersionedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isProveSuccess", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "layer2ChainId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proveState", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_proof", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "proveStatus", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateVerifier", + "inputs": [ + { + "name": "_verifier", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifier", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } + ], + "bytecode": { + "object": "0x60a060405234801562000010575f80fd5b50604051620012dc380380620012dc833981810160405281019062000036919062000229565b620000566200004a620000ba60201b60201c565b620000c160201b60201c565b8167ffffffffffffffff1660808167ffffffffffffffff16815250508060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506200026e565b5f33905090565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f80fd5b5f67ffffffffffffffff82169050919050565b620001a48162000186565b8114620001af575f80fd5b50565b5f81519050620001c28162000199565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620001f382620001c8565b9050919050565b6200020581620001e7565b811462000210575f80fd5b50565b5f815190506200022381620001fa565b92915050565b5f806040838503121562000242576200024162000182565b5b5f6200025185828601620001b2565b9250506020620002648582860162000213565b9150509250929050565b60805161104e6200028e5f395f8181610215015261033e015261104e5ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063715018a61161006f578063715018a6146101675780638da5cb5b1461017157806397fc007c1461018f578063d181ed76146101ab578063e7047c04146101c7578063f2fde38b146101f7576100a7565b806303c7f4af146100ab5780630b79cdda146100c957806325684280146100fd5780632b7ac3f31461012d57806359ef11201461014b575b5f80fd5b6100b3610213565b6040516100c091906107cd565b60405180910390f35b6100e360048036038101906100de9190610821565b610237565b6040516100f4959493929190610864565b60405180910390f35b61011760048036038101906101129190610821565b610269565b60405161012491906108cf565b60405180910390f35b6101356102d1565b6040516101429190610927565b60405180910390f35b610165600480360381019061016091906109cb565b6102f6565b005b61016f61050a565b005b61017961051d565b6040516101869190610927565b60405180910390f35b6101a960048036038101906101a49190610a52565b610544565b005b6101c560048036038101906101c09190610a9f565b61058f565b005b6101e160048036038101906101dc9190610821565b6105c6565b6040516101ee91906108cf565b60405180910390f35b610211600480360381019061020c9190610a52565b6105e3565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b6002602052805f5260405f205f91509050805f0154908060010154908060020154908060030154908060040154905085565b5f8082116102ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a390610b37565b60405180910390fd5b60035f8381526020019081526020015f205f9054906101000a900460ff169050919050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f828290501161033b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033290610b9f565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000060025f8667ffffffffffffffff1681526020019081526020015f205f015460025f8767ffffffffffffffff1681526020019081526020015f206001015460025f8867ffffffffffffffff1681526020019081526020015f20600201545f801b60025f8a67ffffffffffffffff1681526020019081526020015f206003015460025f8b67ffffffffffffffff1681526020019081526020015f20600401546040516020016104109796959493929190610c11565b60405160208183030381529060405280519060200120905060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b768f1c98484846040516020016104789190610c91565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016104a593929190610d6f565b5f6040518083038186803b1580156104bb575f80fd5b505afa1580156104cd573d5f803e3d5ffd5b50505050600160035f8667ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050505050565b610512610665565b61051b5f6106e3565b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054c610665565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610597610665565b8060025f8467ffffffffffffffff1681526020019081526020015f2081816105bf9190610f14565b9050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6105eb610665565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610659576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065090610f92565b60405180910390fd5b610662816106e3565b50565b61066d6107a4565b73ffffffffffffffffffffffffffffffffffffffff1661068b61051d565b73ffffffffffffffffffffffffffffffffffffffff16146106e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d890610ffa565b60405180910390fd5b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f33905090565b5f67ffffffffffffffff82169050919050565b6107c7816107ab565b82525050565b5f6020820190506107e05f8301846107be565b92915050565b5f80fd5b5f80fd5b5f819050919050565b610800816107ee565b811461080a575f80fd5b50565b5f8135905061081b816107f7565b92915050565b5f60208284031215610836576108356107e6565b5b5f6108438482850161080d565b91505092915050565b5f819050919050565b61085e8161084c565b82525050565b5f60a0820190506108775f830188610855565b6108846020830187610855565b6108916040830186610855565b61089e6060830185610855565b6108ab6080830184610855565b9695505050505050565b5f8115159050919050565b6108c9816108b5565b82525050565b5f6020820190506108e25f8301846108c0565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610911826108e8565b9050919050565b61092181610907565b82525050565b5f60208201905061093a5f830184610918565b92915050565b610949816107ab565b8114610953575f80fd5b50565b5f8135905061096481610940565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261098b5761098a61096a565b5b8235905067ffffffffffffffff8111156109a8576109a761096e565b5b6020830191508360018202830111156109c4576109c3610972565b5b9250929050565b5f805f604084860312156109e2576109e16107e6565b5b5f6109ef86828701610956565b935050602084013567ffffffffffffffff811115610a1057610a0f6107ea565b5b610a1c86828701610976565b92509250509250925092565b610a3181610907565b8114610a3b575f80fd5b50565b5f81359050610a4c81610a28565b92915050565b5f60208284031215610a6757610a666107e6565b5b5f610a7484828501610a3e565b91505092915050565b5f80fd5b5f60a08284031215610a9657610a95610a7d565b5b81905092915050565b5f8060c08385031215610ab557610ab46107e6565b5b5f610ac285828601610956565b9250506020610ad385828601610a81565b9150509250929050565b5f82825260208201905092915050565b7f696e76616c6964206261746368496e64657800000000000000000000000000005f82015250565b5f610b21601283610add565b9150610b2c82610aed565b602082019050919050565b5f6020820190508181035f830152610b4e81610b15565b9050919050565b7f496e76616c6964207a6b2070726f6f66000000000000000000000000000000005f82015250565b5f610b89601083610add565b9150610b9482610b55565b602082019050919050565b5f6020820190508181035f830152610bb681610b7d565b9050919050565b5f8160c01b9050919050565b5f610bd382610bbd565b9050919050565b610beb610be6826107ab565b610bc9565b82525050565b5f819050919050565b610c0b610c068261084c565b610bf1565b82525050565b5f610c1c828a610bda565b600882019150610c2c8289610bfa565b602082019150610c3c8288610bfa565b602082019150610c4c8287610bfa565b602082019150610c5c8286610bfa565b602082019150610c6c8285610bfa565b602082019150610c7c8284610bfa565b60208201915081905098975050505050505050565b5f610c9c8284610bfa565b60208201915081905092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f610ce48385610cab565b9350610cf1838584610cbb565b610cfa83610cc9565b840190509392505050565b5f81519050919050565b5f5b83811015610d2c578082015181840152602081019050610d11565b5f8484015250505050565b5f610d4182610d05565b610d4b8185610cab565b9350610d5b818560208601610d0f565b610d6481610cc9565b840191505092915050565b5f6040820190508181035f830152610d88818587610cd9565b90508181036020830152610d9c8184610d37565b9050949350505050565b610daf8161084c565b8114610db9575f80fd5b50565b5f8135610dc881610da6565b80915050919050565b5f815f1b9050919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610e0784610dd1565b9350801983169250808416831791505092915050565b5f610e278261084c565b9050919050565b5f815f1c9050919050565b5f610e4382610e2e565b9050919050565b610e5382610e1d565b610e66610e5f82610e39565b8354610ddc565b8255505050565b5f81015f830180610e7d81610dbc565b9050610e898184610e4a565b505050600181016020830180610e9e81610dbc565b9050610eaa8184610e4a565b505050600281016040830180610ebf81610dbc565b9050610ecb8184610e4a565b505050600381016060830180610ee081610dbc565b9050610eec8184610e4a565b505050600481016080830180610f0181610dbc565b9050610f0d8184610e4a565b5050505050565b610f1e8282610e6d565b5050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b5f610f7c602683610add565b9150610f8782610f22565b604082019050919050565b5f6020820190508181035f830152610fa981610f70565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f82015250565b5f610fe4602083610add565b9150610fef82610fb0565b602082019050919050565b5f6020820190508181035f83015261101181610fd8565b905091905056fea2646970667358221220e56002070fb4c68e802e5ce65eb8314d43691042bf73f4658dd277afa9b08e5564736f6c63430008180033", + "sourceMap": "219:2276:21:-:0;;;837:119;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;929:32:20;948:12;:10;;;:12;;:::i;:::-;929:18;;;:32;;:::i;:::-;911:8:21;895:24;;;;;;;;;;940:9;929:8;;:20;;;;;;;;;;;;;;;;;;837:119;;219:2276;;655:96:19;708:7;734:10;727:17;;655:96;:::o;2419:187:20:-;2492:16;2511:6;;;;;;;;;;;2492:25;;2536:8;2527:6;;:17;;;;;;;;;;;;;;;;;;2590:8;2559:40;;2580:8;2559:40;;;;;;;;;;;;2482:124;2419:187;:::o;88:117:27:-;197:1;194;187:12;334:101;370:7;410:18;403:5;399:30;388:41;;334:101;;;:::o;441:120::-;513:23;530:5;513:23;:::i;:::-;506:5;503:34;493:62;;551:1;548;541:12;493:62;441:120;:::o;567:141::-;623:5;654:6;648:13;639:22;;670:32;696:5;670:32;:::i;:::-;567:141;;;;:::o;714:126::-;751:7;791:42;784:5;780:54;769:65;;714:126;;;:::o;846:96::-;883:7;912:24;930:5;912:24;:::i;:::-;901:35;;846:96;;;:::o;948:122::-;1021:24;1039:5;1021:24;:::i;:::-;1014:5;1011:35;1001:63;;1060:1;1057;1050:12;1001:63;948:122;:::o;1076:143::-;1133:5;1164:6;1158:13;1149:22;;1180:33;1207:5;1180:33;:::i;:::-;1076:143;;;;:::o;1225:505::-;1303:6;1311;1360:2;1348:9;1339:7;1335:23;1331:32;1328:119;;;1366:79;;:::i;:::-;1328:119;1486:1;1511:63;1566:7;1557:6;1546:9;1542:22;1511:63;:::i;:::-;1501:73;;1457:127;1623:2;1649:64;1705:7;1696:6;1685:9;1681:22;1649:64;:::i;:::-;1639:74;;1594:129;1225:505;;;;;:::o;219:2276:21:-;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063715018a61161006f578063715018a6146101675780638da5cb5b1461017157806397fc007c1461018f578063d181ed76146101ab578063e7047c04146101c7578063f2fde38b146101f7576100a7565b806303c7f4af146100ab5780630b79cdda146100c957806325684280146100fd5780632b7ac3f31461012d57806359ef11201461014b575b5f80fd5b6100b3610213565b6040516100c091906107cd565b60405180910390f35b6100e360048036038101906100de9190610821565b610237565b6040516100f4959493929190610864565b60405180910390f35b61011760048036038101906101129190610821565b610269565b60405161012491906108cf565b60405180910390f35b6101356102d1565b6040516101429190610927565b60405180910390f35b610165600480360381019061016091906109cb565b6102f6565b005b61016f61050a565b005b61017961051d565b6040516101869190610927565b60405180910390f35b6101a960048036038101906101a49190610a52565b610544565b005b6101c560048036038101906101c09190610a9f565b61058f565b005b6101e160048036038101906101dc9190610821565b6105c6565b6040516101ee91906108cf565b60405180910390f35b610211600480360381019061020c9190610a52565b6105e3565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b6002602052805f5260405f205f91509050805f0154908060010154908060020154908060030154908060040154905085565b5f8082116102ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a390610b37565b60405180910390fd5b60035f8381526020019081526020015f205f9054906101000a900460ff169050919050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f828290501161033b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033290610b9f565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000060025f8667ffffffffffffffff1681526020019081526020015f205f015460025f8767ffffffffffffffff1681526020019081526020015f206001015460025f8867ffffffffffffffff1681526020019081526020015f20600201545f801b60025f8a67ffffffffffffffff1681526020019081526020015f206003015460025f8b67ffffffffffffffff1681526020019081526020015f20600401546040516020016104109796959493929190610c11565b60405160208183030381529060405280519060200120905060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b768f1c98484846040516020016104789190610c91565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016104a593929190610d6f565b5f6040518083038186803b1580156104bb575f80fd5b505afa1580156104cd573d5f803e3d5ffd5b50505050600160035f8667ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050505050565b610512610665565b61051b5f6106e3565b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054c610665565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610597610665565b8060025f8467ffffffffffffffff1681526020019081526020015f2081816105bf9190610f14565b9050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6105eb610665565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610659576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065090610f92565b60405180910390fd5b610662816106e3565b50565b61066d6107a4565b73ffffffffffffffffffffffffffffffffffffffff1661068b61051d565b73ffffffffffffffffffffffffffffffffffffffff16146106e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d890610ffa565b60405180910390fd5b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f33905090565b5f67ffffffffffffffff82169050919050565b6107c7816107ab565b82525050565b5f6020820190506107e05f8301846107be565b92915050565b5f80fd5b5f80fd5b5f819050919050565b610800816107ee565b811461080a575f80fd5b50565b5f8135905061081b816107f7565b92915050565b5f60208284031215610836576108356107e6565b5b5f6108438482850161080d565b91505092915050565b5f819050919050565b61085e8161084c565b82525050565b5f60a0820190506108775f830188610855565b6108846020830187610855565b6108916040830186610855565b61089e6060830185610855565b6108ab6080830184610855565b9695505050505050565b5f8115159050919050565b6108c9816108b5565b82525050565b5f6020820190506108e25f8301846108c0565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610911826108e8565b9050919050565b61092181610907565b82525050565b5f60208201905061093a5f830184610918565b92915050565b610949816107ab565b8114610953575f80fd5b50565b5f8135905061096481610940565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261098b5761098a61096a565b5b8235905067ffffffffffffffff8111156109a8576109a761096e565b5b6020830191508360018202830111156109c4576109c3610972565b5b9250929050565b5f805f604084860312156109e2576109e16107e6565b5b5f6109ef86828701610956565b935050602084013567ffffffffffffffff811115610a1057610a0f6107ea565b5b610a1c86828701610976565b92509250509250925092565b610a3181610907565b8114610a3b575f80fd5b50565b5f81359050610a4c81610a28565b92915050565b5f60208284031215610a6757610a666107e6565b5b5f610a7484828501610a3e565b91505092915050565b5f80fd5b5f60a08284031215610a9657610a95610a7d565b5b81905092915050565b5f8060c08385031215610ab557610ab46107e6565b5b5f610ac285828601610956565b9250506020610ad385828601610a81565b9150509250929050565b5f82825260208201905092915050565b7f696e76616c6964206261746368496e64657800000000000000000000000000005f82015250565b5f610b21601283610add565b9150610b2c82610aed565b602082019050919050565b5f6020820190508181035f830152610b4e81610b15565b9050919050565b7f496e76616c6964207a6b2070726f6f66000000000000000000000000000000005f82015250565b5f610b89601083610add565b9150610b9482610b55565b602082019050919050565b5f6020820190508181035f830152610bb681610b7d565b9050919050565b5f8160c01b9050919050565b5f610bd382610bbd565b9050919050565b610beb610be6826107ab565b610bc9565b82525050565b5f819050919050565b610c0b610c068261084c565b610bf1565b82525050565b5f610c1c828a610bda565b600882019150610c2c8289610bfa565b602082019150610c3c8288610bfa565b602082019150610c4c8287610bfa565b602082019150610c5c8286610bfa565b602082019150610c6c8285610bfa565b602082019150610c7c8284610bfa565b60208201915081905098975050505050505050565b5f610c9c8284610bfa565b60208201915081905092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f610ce48385610cab565b9350610cf1838584610cbb565b610cfa83610cc9565b840190509392505050565b5f81519050919050565b5f5b83811015610d2c578082015181840152602081019050610d11565b5f8484015250505050565b5f610d4182610d05565b610d4b8185610cab565b9350610d5b818560208601610d0f565b610d6481610cc9565b840191505092915050565b5f6040820190508181035f830152610d88818587610cd9565b90508181036020830152610d9c8184610d37565b9050949350505050565b610daf8161084c565b8114610db9575f80fd5b50565b5f8135610dc881610da6565b80915050919050565b5f815f1b9050919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610e0784610dd1565b9350801983169250808416831791505092915050565b5f610e278261084c565b9050919050565b5f815f1c9050919050565b5f610e4382610e2e565b9050919050565b610e5382610e1d565b610e66610e5f82610e39565b8354610ddc565b8255505050565b5f81015f830180610e7d81610dbc565b9050610e898184610e4a565b505050600181016020830180610e9e81610dbc565b9050610eaa8184610e4a565b505050600281016040830180610ebf81610dbc565b9050610ecb8184610e4a565b505050600381016060830180610ee081610dbc565b9050610eec8184610e4a565b505050600481016080830180610f0181610dbc565b9050610f0d8184610e4a565b5050505050565b610f1e8282610e6d565b5050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b5f610f7c602683610add565b9150610f8782610f22565b604082019050919050565b5f6020820190508181035f830152610fa981610f70565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f82015250565b5f610fe4602083610add565b9150610fef82610fb0565b602082019050919050565b5f6020820190508181035f83015261101181610fd8565b905091905056fea2646970667358221220e56002070fb4c68e802e5ce65eb8314d43691042bf73f4658dd277afa9b08e5564736f6c63430008180033", + "sourceMap": "219:2276:21:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;323:37;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;629:58;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;2315:178;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;413:23;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1333:817;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1817:101:20;;;:::i;:::-;;1194:85;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2210:99:21;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1116:155;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;722:43;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2067:198:20;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;323:37:21;;;:::o;629:58::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;2315:178::-;2383:4;2421:1;2407:11;:15;2399:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;2462:11;:24;2474:11;2462:24;;;;;;;;;;;;;;;;;;;;;2455:31;;2315:178;;;:::o;413:23::-;;;;;;;;;;;;;:::o;1333:817::-;1474:1;1458:6;;:13;;:17;1450:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;1507:24;1591:13;1622:20;:33;1643:11;1622:33;;;;;;;;;;;;;:47;;;1687:20;:33;1708:11;1687:33;;;;;;;;;;;;;:47;;;1752:20;:33;1773:11;1752:33;;;;;;;;;;;;;:48;;;1826:1;1818:10;;1846:20;:33;1867:11;1846:33;;;;;;;;;;;;;:42;;;1906:20;:33;1927:11;1906:33;;;;;;;;;;;;;:51;;;1557:414;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1534:447;;;;;;1507:474;;2031:8;;;;;;;;;;;2019:38;;;2058:6;;2083:16;2066:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;2019:82;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2139:4;2112:11;:24;2124:11;2112:24;;;;;;;;;;;;;;:31;;;;;;;;;;;;;;;;;;1405:745;1333:817;;;:::o;1817:101:20:-;1087:13;:11;:13::i;:::-;1881:30:::1;1908:1;1881:18;:30::i;:::-;1817:101::o:0;1194:85::-;1240:7;1266:6;;;;;;;;;;;1259:13;;1194:85;:::o;2210:99:21:-;1087:13:20;:11;:13::i;:::-;2293:9:21::1;2282:8;;:20;;;;;;;;;;;;;;;;;;2210:99:::0;:::o;1116:155::-;1087:13:20;:11;:13::i;:::-;1254:10:21::1;1218:20;:33;1239:11;1218:33;;;;;;;;;;;;;:46;;;;;;:::i;:::-;;;;1116:155:::0;;:::o;722:43::-;;;;;;;;;;;;;;;;;;;;;;:::o;2067:198:20:-;1087:13;:11;:13::i;:::-;2175:1:::1;2155:22;;:8;:22;;::::0;2147:73:::1;;;;;;;;;;;;:::i;:::-;;;;;;;;;2230:28;2249:8;2230:18;:28::i;:::-;2067:198:::0;:::o;1352:130::-;1426:12;:10;:12::i;:::-;1415:23;;:7;:5;:7::i;:::-;:23;;;1407:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;1352:130::o;2419:187::-;2492:16;2511:6;;;;;;;;;;;2492:25;;2536:8;2527:6;;:17;;;;;;;;;;;;;;;;;;2590:8;2559:40;;2580:8;2559:40;;;;;;;;;;;;2482:124;2419:187;:::o;655:96:19:-;708:7;734:10;727:17;;655:96;:::o;7:101:27:-;43:7;83:18;76:5;72:30;61:41;;7:101;;;:::o;114:115::-;199:23;216:5;199:23;:::i;:::-;194:3;187:36;114:115;;:::o;235:218::-;326:4;364:2;353:9;349:18;341:26;;377:69;443:1;432:9;428:17;419:6;377:69;:::i;:::-;235:218;;;;:::o;540:117::-;649:1;646;639:12;663:117;772:1;769;762:12;786:77;823:7;852:5;841:16;;786:77;;;:::o;869:122::-;942:24;960:5;942:24;:::i;:::-;935:5;932:35;922:63;;981:1;978;971:12;922:63;869:122;:::o;997:139::-;1043:5;1081:6;1068:20;1059:29;;1097:33;1124:5;1097:33;:::i;:::-;997:139;;;;:::o;1142:329::-;1201:6;1250:2;1238:9;1229:7;1225:23;1221:32;1218:119;;;1256:79;;:::i;:::-;1218:119;1376:1;1401:53;1446:7;1437:6;1426:9;1422:22;1401:53;:::i;:::-;1391:63;;1347:117;1142:329;;;;:::o;1477:77::-;1514:7;1543:5;1532:16;;1477:77;;;:::o;1560:118::-;1647:24;1665:5;1647:24;:::i;:::-;1642:3;1635:37;1560:118;;:::o;1684:664::-;1889:4;1927:3;1916:9;1912:19;1904:27;;1941:71;2009:1;1998:9;1994:17;1985:6;1941:71;:::i;:::-;2022:72;2090:2;2079:9;2075:18;2066:6;2022:72;:::i;:::-;2104;2172:2;2161:9;2157:18;2148:6;2104:72;:::i;:::-;2186;2254:2;2243:9;2239:18;2230:6;2186:72;:::i;:::-;2268:73;2336:3;2325:9;2321:19;2312:6;2268:73;:::i;:::-;1684:664;;;;;;;;:::o;2354:90::-;2388:7;2431:5;2424:13;2417:21;2406:32;;2354:90;;;:::o;2450:109::-;2531:21;2546:5;2531:21;:::i;:::-;2526:3;2519:34;2450:109;;:::o;2565:210::-;2652:4;2690:2;2679:9;2675:18;2667:26;;2703:65;2765:1;2754:9;2750:17;2741:6;2703:65;:::i;:::-;2565:210;;;;:::o;2781:126::-;2818:7;2858:42;2851:5;2847:54;2836:65;;2781:126;;;:::o;2913:96::-;2950:7;2979:24;2997:5;2979:24;:::i;:::-;2968:35;;2913:96;;;:::o;3015:118::-;3102:24;3120:5;3102:24;:::i;:::-;3097:3;3090:37;3015:118;;:::o;3139:222::-;3232:4;3270:2;3259:9;3255:18;3247:26;;3283:71;3351:1;3340:9;3336:17;3327:6;3283:71;:::i;:::-;3139:222;;;;:::o;3367:120::-;3439:23;3456:5;3439:23;:::i;:::-;3432:5;3429:34;3419:62;;3477:1;3474;3467:12;3419:62;3367:120;:::o;3493:137::-;3538:5;3576:6;3563:20;3554:29;;3592:32;3618:5;3592:32;:::i;:::-;3493:137;;;;:::o;3636:117::-;3745:1;3742;3735:12;3759:117;3868:1;3865;3858:12;3882:117;3991:1;3988;3981:12;4018:552;4075:8;4085:6;4135:3;4128:4;4120:6;4116:17;4112:27;4102:122;;4143:79;;:::i;:::-;4102:122;4256:6;4243:20;4233:30;;4286:18;4278:6;4275:30;4272:117;;;4308:79;;:::i;:::-;4272:117;4422:4;4414:6;4410:17;4398:29;;4476:3;4468:4;4460:6;4456:17;4446:8;4442:32;4439:41;4436:128;;;4483:79;;:::i;:::-;4436:128;4018:552;;;;;:::o;4576:670::-;4654:6;4662;4670;4719:2;4707:9;4698:7;4694:23;4690:32;4687:119;;;4725:79;;:::i;:::-;4687:119;4845:1;4870:52;4914:7;4905:6;4894:9;4890:22;4870:52;:::i;:::-;4860:62;;4816:116;4999:2;4988:9;4984:18;4971:32;5030:18;5022:6;5019:30;5016:117;;;5052:79;;:::i;:::-;5016:117;5165:64;5221:7;5212:6;5201:9;5197:22;5165:64;:::i;:::-;5147:82;;;;4942:297;4576:670;;;;;:::o;5252:122::-;5325:24;5343:5;5325:24;:::i;:::-;5318:5;5315:35;5305:63;;5364:1;5361;5354:12;5305:63;5252:122;:::o;5380:139::-;5426:5;5464:6;5451:20;5442:29;;5480:33;5507:5;5480:33;:::i;:::-;5380:139;;;;:::o;5525:329::-;5584:6;5633:2;5621:9;5612:7;5608:23;5604:32;5601:119;;;5639:79;;:::i;:::-;5601:119;5759:1;5784:53;5829:7;5820:6;5809:9;5805:22;5784:53;:::i;:::-;5774:63;;5730:117;5525:329;;;;:::o;5860:117::-;5969:1;5966;5959:12;6021:236;6098:5;6139:3;6130:6;6125:3;6121:16;6117:26;6114:113;;;6146:79;;:::i;:::-;6114:113;6245:6;6236:15;;6021:236;;;;:::o;6263:535::-;6361:6;6369;6418:3;6406:9;6397:7;6393:23;6389:33;6386:120;;;6425:79;;:::i;:::-;6386:120;6545:1;6570:52;6614:7;6605:6;6594:9;6590:22;6570:52;:::i;:::-;6560:62;;6516:116;6671:2;6697:84;6773:7;6764:6;6753:9;6749:22;6697:84;:::i;:::-;6687:94;;6642:149;6263:535;;;;;:::o;6804:169::-;6888:11;6922:6;6917:3;6910:19;6962:4;6957:3;6953:14;6938:29;;6804:169;;;;:::o;6979:168::-;7119:20;7115:1;7107:6;7103:14;7096:44;6979:168;:::o;7153:366::-;7295:3;7316:67;7380:2;7375:3;7316:67;:::i;:::-;7309:74;;7392:93;7481:3;7392:93;:::i;:::-;7510:2;7505:3;7501:12;7494:19;;7153:366;;;:::o;7525:419::-;7691:4;7729:2;7718:9;7714:18;7706:26;;7778:9;7772:4;7768:20;7764:1;7753:9;7749:17;7742:47;7806:131;7932:4;7806:131;:::i;:::-;7798:139;;7525:419;;;:::o;7950:166::-;8090:18;8086:1;8078:6;8074:14;8067:42;7950:166;:::o;8122:366::-;8264:3;8285:67;8349:2;8344:3;8285:67;:::i;:::-;8278:74;;8361:93;8450:3;8361:93;:::i;:::-;8479:2;8474:3;8470:12;8463:19;;8122:366;;;:::o;8494:419::-;8660:4;8698:2;8687:9;8683:18;8675:26;;8747:9;8741:4;8737:20;8733:1;8722:9;8718:17;8711:47;8775:131;8901:4;8775:131;:::i;:::-;8767:139;;8494:419;;;:::o;8919:96::-;8953:8;9002:5;8997:3;8993:15;8972:36;;8919:96;;;:::o;9021:94::-;9059:7;9088:21;9103:5;9088:21;:::i;:::-;9077:32;;9021:94;;;:::o;9121:153::-;9224:43;9243:23;9260:5;9243:23;:::i;:::-;9224:43;:::i;:::-;9219:3;9212:56;9121:153;;:::o;9280:79::-;9319:7;9348:5;9337:16;;9280:79;;;:::o;9365:157::-;9470:45;9490:24;9508:5;9490:24;:::i;:::-;9470:45;:::i;:::-;9465:3;9458:58;9365:157;;:::o;9528:1097::-;9806:3;9821:73;9890:3;9881:6;9821:73;:::i;:::-;9919:1;9914:3;9910:11;9903:18;;9931:75;10002:3;9993:6;9931:75;:::i;:::-;10031:2;10026:3;10022:12;10015:19;;10044:75;10115:3;10106:6;10044:75;:::i;:::-;10144:2;10139:3;10135:12;10128:19;;10157:75;10228:3;10219:6;10157:75;:::i;:::-;10257:2;10252:3;10248:12;10241:19;;10270:75;10341:3;10332:6;10270:75;:::i;:::-;10370:2;10365:3;10361:12;10354:19;;10383:75;10454:3;10445:6;10383:75;:::i;:::-;10483:2;10478:3;10474:12;10467:19;;10496:75;10567:3;10558:6;10496:75;:::i;:::-;10596:2;10591:3;10587:12;10580:19;;10616:3;10609:10;;9528:1097;;;;;;;;;;:::o;10631:256::-;10743:3;10758:75;10829:3;10820:6;10758:75;:::i;:::-;10858:2;10853:3;10849:12;10842:19;;10878:3;10871:10;;10631:256;;;;:::o;10893:168::-;10976:11;11010:6;11005:3;10998:19;11050:4;11045:3;11041:14;11026:29;;10893:168;;;;:::o;11067:146::-;11164:6;11159:3;11154;11141:30;11205:1;11196:6;11191:3;11187:16;11180:27;11067:146;;;:::o;11219:102::-;11260:6;11311:2;11307:7;11302:2;11295:5;11291:14;11287:28;11277:38;;11219:102;;;:::o;11349:314::-;11445:3;11466:70;11529:6;11524:3;11466:70;:::i;:::-;11459:77;;11546:56;11595:6;11590:3;11583:5;11546:56;:::i;:::-;11627:29;11649:6;11627:29;:::i;:::-;11622:3;11618:39;11611:46;;11349:314;;;;;:::o;11669:98::-;11720:6;11754:5;11748:12;11738:22;;11669:98;;;:::o;11773:246::-;11854:1;11864:113;11878:6;11875:1;11872:13;11864:113;;;11963:1;11958:3;11954:11;11948:18;11944:1;11939:3;11935:11;11928:39;11900:2;11897:1;11893:10;11888:15;;11864:113;;;12011:1;12002:6;11997:3;11993:16;11986:27;11835:184;11773:246;;;:::o;12025:373::-;12111:3;12139:38;12171:5;12139:38;:::i;:::-;12193:70;12256:6;12251:3;12193:70;:::i;:::-;12186:77;;12272:65;12330:6;12325:3;12318:4;12311:5;12307:16;12272:65;:::i;:::-;12362:29;12384:6;12362:29;:::i;:::-;12357:3;12353:39;12346:46;;12115:283;12025:373;;;;:::o;12404:526::-;12571:4;12609:2;12598:9;12594:18;12586:26;;12658:9;12652:4;12648:20;12644:1;12633:9;12629:17;12622:47;12686:86;12767:4;12758:6;12750;12686:86;:::i;:::-;12678:94;;12819:9;12813:4;12809:20;12804:2;12793:9;12789:18;12782:48;12847:76;12918:4;12909:6;12847:76;:::i;:::-;12839:84;;12404:526;;;;;;:::o;13122:122::-;13195:24;13213:5;13195:24;:::i;:::-;13188:5;13185:35;13175:63;;13234:1;13231;13224:12;13175:63;13122:122;:::o;13250:186::-;13295:11;13344:3;13331:17;13357:33;13384:5;13357:33;:::i;:::-;13424:5;13400:29;;13307:129;13250:186;;;:::o;13442:92::-;13474:8;13521:5;13518:1;13514:13;13493:34;;13442:92;;;:::o;13540:290::-;13598:6;13627:66;13714:22;13727:8;13714:22;:::i;:::-;13702:34;;13769:4;13765:9;13758:5;13754:21;13745:30;;13818:4;13808:8;13804:19;13797:5;13794:30;13784:40;;13605:225;13540:290;;;;:::o;13836:113::-;13886:9;13919:24;13937:5;13919:24;:::i;:::-;13906:37;;13836:113;;;:::o;13955:102::-;13997:8;14044:5;14041:1;14037:13;14016:34;;13955:102;;;:::o;14063:99::-;14106:3;14127:29;14150:5;14127:29;:::i;:::-;14120:36;;14063:99;;;:::o;14168:262::-;14278:39;14309:7;14278:39;:::i;:::-;14339:84;14381:41;14405:16;14381:41;:::i;:::-;14374:4;14368:11;14339:84;:::i;:::-;14333:4;14326:98;14244:186;14168:262;;:::o;14436:1828::-;14620:1;14614:4;14610:12;14666:1;14659:5;14655:13;14716:12;14759:42;14787:13;14759:42;:::i;:::-;14742:59;;14815:78;14879:13;14867:10;14815:78;:::i;:::-;14577:327;;;14957:1;14951:4;14947:12;15003:2;14996:5;14992:14;15054:12;15097:42;15125:13;15097:42;:::i;:::-;15080:59;;15153:78;15217:13;15205:10;15153:78;:::i;:::-;14914:328;;;15295:1;15289:4;15285:12;15341:2;15334:5;15330:14;15392:12;15435:42;15463:13;15435:42;:::i;:::-;15418:59;;15491:78;15555:13;15543:10;15491:78;:::i;:::-;15252:328;;;15633:1;15627:4;15623:12;15679:2;15672:5;15668:14;15730:12;15773:42;15801:13;15773:42;:::i;:::-;15756:59;;15829:78;15893:13;15881:10;15829:78;:::i;:::-;15590:328;;;15971:1;15965:4;15961:12;16017:3;16010:5;16006:15;16069:12;16112:42;16140:13;16112:42;:::i;:::-;16095:59;;16168:78;16232:13;16220:10;16168:78;:::i;:::-;15928:329;;;14436:1828;;:::o;16270:272::-;16414:122;16528:7;16522:4;16414:122;:::i;:::-;16270:272;;:::o;16548:225::-;16688:34;16684:1;16676:6;16672:14;16665:58;16757:8;16752:2;16744:6;16740:15;16733:33;16548:225;:::o;16779:366::-;16921:3;16942:67;17006:2;17001:3;16942:67;:::i;:::-;16935:74;;17018:93;17107:3;17018:93;:::i;:::-;17136:2;17131:3;17127:12;17120:19;;16779:366;;;:::o;17151:419::-;17317:4;17355:2;17344:9;17340:18;17332:26;;17404:9;17398:4;17394:20;17390:1;17379:9;17375:17;17368:47;17432:131;17558:4;17432:131;:::i;:::-;17424:139;;17151:419;;;:::o;17576:182::-;17716:34;17712:1;17704:6;17700:14;17693:58;17576:182;:::o;17764:366::-;17906:3;17927:67;17991:2;17986:3;17927:67;:::i;:::-;17920:74;;18003:93;18092:3;18003:93;:::i;:::-;18121:2;18116:3;18112:12;18105:19;;17764:366;;;:::o;18136:419::-;18302:4;18340:2;18329:9;18325:18;18317:26;;18389:9;18383:4;18379:20;18375:1;18364:9;18360:17;18353:47;18417:131;18543:4;18417:131;:::i;:::-;18409:139;;18136:419;;;:::o", + "linkReferences": {}, + "immutableReferences": { + "41510": [ + { + "start": 533, + "length": 32 + }, + { + "start": 830, + "length": 32 + } + ] + } + }, + "methodIdentifiers": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": "d181ed76", + "committedBatchStores(uint256)": "0b79cdda", + "isProveSuccess(uint256)": "25684280", + "layer2ChainId()": "03c7f4af", + "owner()": "8da5cb5b", + "proveState(uint64,bytes)": "59ef1120", + "proveStatus(uint256)": "e7047c04", + "renounceOwnership()": "715018a6", + "transferOwnership(address)": "f2fde38b", + "updateVerifier(address)": "97fc007c", + "verifier()": "2b7ac3f3" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ShadowRollup.BatchStore\",\"name\":\"_batchData\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatchStores\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isProveSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"proveStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"params\":{\"_batchData\":\"The batch data\",\"_batchIndex\":\"The index of batch\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ShadowRollup\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"notice\":\"Commit a batch of transactions on layer 1.\"},\"layer2ChainId()\":{\"notice\":\"The chain id of the corresponding layer 2 chain.\"},\"updateVerifier(address)\":{\"notice\":\"Update the address verifier contract.\"},\"verifier()\":{\"notice\":\"The address of zkvm verifier.\"}},\"notice\":\"This contract maintains data for shadow rollup.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ShadowRollup.sol\":\"ShadowRollup\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/Context.sol\":{\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c\",\"dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h\"]},\"src/Ownable.sol\":{\"keccak256\":\"0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a\",\"dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB\"]},\"src/ShadowRollup.sol\":{\"keccak256\":\"0x904fc5504d39f106e724f054e70cf9dd6834045ed96d26d7721deda97dcf361c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0c12d8b897446a1fd27d4965ad9c0516e93e125c900fe1de87f6082b9ad51cca\",\"dweb:/ipfs/Qmce7X5ouUckXue4dV6uvr9KbewknMjiNfYGXNbTFy2hMX\"]},\"src/libs/EvmVerifier.sol\":{\"keccak256\":\"0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2\",\"dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR\"]},\"src/libs/ISP1Verifier.sol\":{\"keccak256\":\"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3\",\"dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q\"]},\"src/libs/PlonkVerifier.sol\":{\"keccak256\":\"0x806fd8b6b4ade67af043f4fa5f4115274d818322357d4204658baa0e89d8a22b\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://ea68e04099672760854887295478f8849aa4bc9c45aac86735817b60ef93dff6\",\"dweb:/ipfs/QmbPVzAyYKiJPAjXQ1jAya7ozzhKYFmPL81akrjgyEirhf\"]},\"src/libs/SP1VerifierPlonk.sol\":{\"keccak256\":\"0x3b0264e71c5994b11eac26bd62d86f2d1d83b1ea80cf4ed1b63040af33d48c0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://10d2be89afab2db15a1d3e2c3f197aa447e09ef012411f24cb12941bab9ac445\",\"dweb:/ipfs/QmfHGw55LFKqSH6unUTQgFzMwZ1T6ZeinpBxgnUJ4ayxoP\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.24+commit.e11b9ed9" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainId", + "type": "uint64" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousOwner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "OwnershipTransferred", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_batchIndex", + "type": "uint64" + }, + { + "internalType": "struct ShadowRollup.BatchStore", + "name": "_batchData", + "type": "tuple", + "components": [ + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "dataHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ] + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "commitBatch" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "committedBatchStores", + "outputs": [ + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "dataHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "isProveSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "layer2ChainId", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "_proof", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "proveState" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "proveStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "name": "renounceOwnership" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transferOwnership" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_verifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "updateVerifier" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": { + "params": { + "_batchData": "The batch data", + "_batchIndex": "The index of batch" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": { + "notice": "Commit a batch of transactions on layer 1." + }, + "layer2ChainId()": { + "notice": "The chain id of the corresponding layer 2 chain." + }, + "updateVerifier(address)": { + "notice": "Update the address verifier contract." + }, + "verifier()": { + "notice": "The address of zkvm verifier." + } + }, + "version": 1 + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/" + ], + "optimizer": { + "enabled": false, + "runs": 200 + }, + "metadata": { + "bytecodeHash": "ipfs" + }, + "compilationTarget": { + "src/ShadowRollup.sol": "ShadowRollup" + }, + "evmVersion": "cancun", + "libraries": {} + }, + "sources": { + "src/Context.sol": { + "keccak256": "0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439", + "urls": [ + "bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c", + "dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h" + ], + "license": "MIT" + }, + "src/Ownable.sol": { + "keccak256": "0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8", + "urls": [ + "bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a", + "dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB" + ], + "license": "MIT" + }, + "src/ShadowRollup.sol": { + "keccak256": "0x904fc5504d39f106e724f054e70cf9dd6834045ed96d26d7721deda97dcf361c", + "urls": [ + "bzz-raw://0c12d8b897446a1fd27d4965ad9c0516e93e125c900fe1de87f6082b9ad51cca", + "dweb:/ipfs/Qmce7X5ouUckXue4dV6uvr9KbewknMjiNfYGXNbTFy2hMX" + ], + "license": "MIT" + }, + "src/libs/EvmVerifier.sol": { + "keccak256": "0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb", + "urls": [ + "bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2", + "dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR" + ], + "license": "MIT" + }, + "src/libs/ISP1Verifier.sol": { + "keccak256": "0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3", + "urls": [ + "bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3", + "dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q" + ], + "license": "MIT" + }, + "src/libs/PlonkVerifier.sol": { + "keccak256": "0x806fd8b6b4ade67af043f4fa5f4115274d818322357d4204658baa0e89d8a22b", + "urls": [ + "bzz-raw://ea68e04099672760854887295478f8849aa4bc9c45aac86735817b60ef93dff6", + "dweb:/ipfs/QmbPVzAyYKiJPAjXQ1jAya7ozzhKYFmPL81akrjgyEirhf" + ], + "license": "Apache-2.0" + }, + "src/libs/SP1VerifierPlonk.sol": { + "keccak256": "0x3b0264e71c5994b11eac26bd62d86f2d1d83b1ea80cf4ed1b63040af33d48c0b", + "urls": [ + "bzz-raw://10d2be89afab2db15a1d3e2c3f197aa447e09ef012411f24cb12941bab9ac445", + "dweb:/ipfs/QmfHGw55LFKqSH6unUTQgFzMwZ1T6ZeinpBxgnUJ4ayxoP" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "id": 21 } \ No newline at end of file diff --git a/prover/bin/shadow-prove/contracts/bytecode/ShadowRollup.json b/prover/bin/shadow-prove/contracts/bytecode/ShadowRollup.json index 0c6177dc5..0a1036a75 100644 --- a/prover/bin/shadow-prove/contracts/bytecode/ShadowRollup.json +++ b/prover/bin/shadow-prove/contracts/bytecode/ShadowRollup.json @@ -1,675 +1,655 @@ { - "abi": [ - { - "type": "constructor", - "inputs": [ - { - "name": "_chainId", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_verifier", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "commitBatch", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_batchData", - "type": "tuple", - "internalType": "struct ShadowRollup.BatchStore", - "components": [ - { - "name": "prevStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "postStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "withdrawalRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "dataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "blobVersionedHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "sequencerSetVerifyHash", - "type": "bytes32", - "internalType": "bytes32" - } - ] - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "committedBatchStores", - "inputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "prevStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "postStateRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "withdrawalRoot", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "dataHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "blobVersionedHash", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "sequencerSetVerifyHash", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isProveSuccess", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "layer2ChainId", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint64", - "internalType": "uint64" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "owner", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "proveState", - "inputs": [ - { - "name": "_batchIndex", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "_proof", - "type": "bytes", - "internalType": "bytes" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proveStatus", - "inputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "renounceOwnership", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferOwnership", - "inputs": [ - { - "name": "newOwner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "updateVerifier", - "inputs": [ - { - "name": "_verifier", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "verifier", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "OwnershipTransferred", - "inputs": [ - { - "name": "previousOwner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "newOwner", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - } - ], - "bytecode": { - "object": "0x60a060405234801561001057600080fd5b5060405161091138038061091183398101604081905261002f916100bb565b6100383361006b565b6001600160401b0391909116608052600180546001600160a01b0319166001600160a01b0390921691909117905561010d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100ce57600080fd5b82516001600160401b03811681146100e557600080fd5b60208401519092506001600160a01b038116811461010257600080fd5b809150509250929050565b6080516107e361012e6000396000818160b3015261032201526107e36000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101c85780638da5cb5b146101d057806397fc007c146101e15780639d049dda146101f4578063e7047c0414610207578063f2fde38b1461022a57600080fd5b806303c7f4af146100ae5780630b79cdda146100f357806325684280146101655780632b7ac3f31461018857806359ef1120146101b3575b600080fd5b6100d57f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610138610101366004610607565b6002602081905260009182526040909120805460018201549282015460038301546004840154600590940154929493919290919086565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016100ea565b610178610173366004610607565b61023d565b60405190151581526020016100ea565b60015461019b906001600160a01b031681565b6040516001600160a01b0390911681526020016100ea565b6101c66101c136600461063d565b61029e565b005b6101c661043e565b6000546001600160a01b031661019b565b6101c66101ef3660046106c0565b610452565b6101c66102023660046106f0565b61047c565b610178610215366004610607565b60036020526000908152604090205460ff1681565b6101c66102383660046106c0565b6104e4565b60008082116102885760405162461bcd60e51b81526020600482015260126024820152710d2dcecc2d8d2c840c4c2e8c6d092dcc8caf60731b60448201526064015b60405180910390fd5b5060009081526003602052604090205460ff1690565b806102de5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103d3590383937b7b360811b604482015260640161027f565b67ffffffffffffffff8316600090815260026020818152604080842080546001820154948201546005830154600384015460049094015494516001600160c01b03197f000000000000000000000000000000000000000000000000000000000000000060c01b1696810196909652602886019290925260488501959095526068840194909452608883019390935260a882019290925260c881019190915260e80160408051808303601f19018152828252805160209182012060015491840181905293506001600160a01b03169163b768f1c99186918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016103e49392919061072f565b60006040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b50505067ffffffffffffffff9094166000908152600360205260409020805460ff1916600117905550505050565b61044661055d565b61045060006105b7565b565b61045a61055d565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61048461055d565b67ffffffffffffffff8216600090815260026020526040902081906104de8282813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a082013560058201555050565b50505050565b6104ec61055d565b6001600160a01b0381166105515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161027f565b61055a816105b7565b50565b6000546001600160a01b031633146104505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161027f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561061957600080fd5b5035919050565b803567ffffffffffffffff8116811461063857600080fd5b919050565b60008060006040848603121561065257600080fd5b61065b84610620565b9250602084013567ffffffffffffffff8082111561067857600080fd5b818601915086601f83011261068c57600080fd5b81358181111561069b57600080fd5b8760208285010111156106ad57600080fd5b6020830194508093505050509250925092565b6000602082840312156106d257600080fd5b81356001600160a01b03811681146106e957600080fd5b9392505050565b60008082840360e081121561070457600080fd5b61070d84610620565b925060c0601f198201121561072157600080fd5b506020830190509250929050565b60408152826040820152828460608301376000606084830101526000601f1980601f860116830160206060858303016020860152855180606084015260005b8181101561078a5787810183015184820160800152820161076e565b50600060808285010152608084601f83011684010194505050505094935050505056fea2646970667358221220f1cf592fa16f148c60584b254200a54483c2809be910a3ee9581d0c69de4d9de64736f6c63430008180033", - "sourceMap": "219:2419:25:-:0;;;878:119;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;929:32:24;734:10:23;929:18:24;:32::i;:::-;-1:-1:-1;;;;;936:24:25;;;;;;970:8;:20;;-1:-1:-1;;;;;;970:20:25;-1:-1:-1;;;;;970:20:25;;;;;;;;;219:2419;;2419:187:24;2492:16;2511:6;;-1:-1:-1;;;;;2527:17:24;;;-1:-1:-1;;;;;;2527:17:24;;;;;;2559:40;;2511:6;;;;;;;2559:40;;2492:16;2559:40;2482:124;2419:187;:::o;14:463:31:-;92:6;100;153:2;141:9;132:7;128:23;124:32;121:52;;;169:1;166;159:12;121:52;195:16;;-1:-1:-1;;;;;240:30:31;;230:41;;220:69;;285:1;282;275:12;220:69;358:2;343:18;;337:25;308:5;;-1:-1:-1;;;;;;393:33:31;;381:46;;371:74;;441:1;438;431:12;371:74;464:7;454:17;;;14:463;;;;;:::o;:::-;219:2419:25;;;;;;;;;;;;;;;;;", - "linkReferences": {} - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101c85780638da5cb5b146101d057806397fc007c146101e15780639d049dda146101f4578063e7047c0414610207578063f2fde38b1461022a57600080fd5b806303c7f4af146100ae5780630b79cdda146100f357806325684280146101655780632b7ac3f31461018857806359ef1120146101b3575b600080fd5b6100d57f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610138610101366004610607565b6002602081905260009182526040909120805460018201549282015460038301546004840154600590940154929493919290919086565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016100ea565b610178610173366004610607565b61023d565b60405190151581526020016100ea565b60015461019b906001600160a01b031681565b6040516001600160a01b0390911681526020016100ea565b6101c66101c136600461063d565b61029e565b005b6101c661043e565b6000546001600160a01b031661019b565b6101c66101ef3660046106c0565b610452565b6101c66102023660046106f0565b61047c565b610178610215366004610607565b60036020526000908152604090205460ff1681565b6101c66102383660046106c0565b6104e4565b60008082116102885760405162461bcd60e51b81526020600482015260126024820152710d2dcecc2d8d2c840c4c2e8c6d092dcc8caf60731b60448201526064015b60405180910390fd5b5060009081526003602052604090205460ff1690565b806102de5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103d3590383937b7b360811b604482015260640161027f565b67ffffffffffffffff8316600090815260026020818152604080842080546001820154948201546005830154600384015460049094015494516001600160c01b03197f000000000000000000000000000000000000000000000000000000000000000060c01b1696810196909652602886019290925260488501959095526068840194909452608883019390935260a882019290925260c881019190915260e80160408051808303601f19018152828252805160209182012060015491840181905293506001600160a01b03169163b768f1c99186918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016103e49392919061072f565b60006040518083038186803b1580156103fc57600080fd5b505afa158015610410573d6000803e3d6000fd5b50505067ffffffffffffffff9094166000908152600360205260409020805460ff1916600117905550505050565b61044661055d565b61045060006105b7565b565b61045a61055d565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b61048461055d565b67ffffffffffffffff8216600090815260026020526040902081906104de8282813581556020820135600182015560408201356002820155606082013560038201556080820135600482015560a082013560058201555050565b50505050565b6104ec61055d565b6001600160a01b0381166105515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161027f565b61055a816105b7565b50565b6000546001600160a01b031633146104505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161027f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561061957600080fd5b5035919050565b803567ffffffffffffffff8116811461063857600080fd5b919050565b60008060006040848603121561065257600080fd5b61065b84610620565b9250602084013567ffffffffffffffff8082111561067857600080fd5b818601915086601f83011261068c57600080fd5b81358181111561069b57600080fd5b8760208285010111156106ad57600080fd5b6020830194508093505050509250925092565b6000602082840312156106d257600080fd5b81356001600160a01b03811681146106e957600080fd5b9392505050565b60008082840360e081121561070457600080fd5b61070d84610620565b925060c0601f198201121561072157600080fd5b506020830190509250929050565b60408152826040820152828460608301376000606084830101526000601f1980601f860116830160206060858303016020860152855180606084015260005b8181101561078a5787810183015184820160800152820161076e565b50600060808285010152608084601f83011684010194505050505094935050505056fea2646970667358221220f1cf592fa16f148c60584b254200a54483c2809be910a3ee9581d0c69de4d9de64736f6c63430008180033", - "sourceMap": "219:2419:25:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;324:37;;;;;;;;188:18:31;176:31;;;158:50;;146:2;131:18;324:37:25;;;;;;;;670:58;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;691:25:31;;;747:2;732:18;;725:34;;;;775:18;;;768:34;;;;833:2;818:18;;811:34;876:3;861:19;;854:35;920:3;905:19;;898:35;678:3;663:19;670:58:25;404:535:31;2458:178:25;;;;;;:::i;:::-;;:::i;:::-;;;1109:14:31;;1102:22;1084:41;;1072:2;1057:18;2458:178:25;944:187:31;414:23:25;;;;;-1:-1:-1;;;;;414:23:25;;;;;;-1:-1:-1;;;;;1300:32:31;;;1282:51;;1270:2;1255:18;414:23:25;1136:203:31;1396:897:25;;;;;;:::i;:::-;;:::i;:::-;;1817:101:24;;;:::i;1194:85::-;1240:7;1266:6;-1:-1:-1;;;;;1266:6:24;1194:85;;2353:99:25;;;;;;:::i;:::-;;:::i;1157:177::-;;;;;;:::i;:::-;;:::i;763:43::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2067:198:24;;;;;;:::i;:::-;;:::i;2458:178:25:-;2526:4;2564:1;2550:11;:15;2542:46;;;;-1:-1:-1;;;2542:46:25;;3032:2:31;2542:46:25;;;3014:21:31;3071:2;3051:18;;;3044:30;-1:-1:-1;;;3090:18:31;;;3083:48;3148:18;;2542:46:25;;;;;;;;;-1:-1:-1;2605:24:25;;;;:11;:24;;;;;;;;;2458:178::o;1396:897::-;1521:17;1513:46;;;;-1:-1:-1;;;1513:46:25;;3379:2:31;1513:46:25;;;3361:21:31;3418:2;3398:18;;;3391:30;-1:-1:-1;;;3437:18:31;;;3430:46;3493:18;;1513:46:25;3177:340:31;1513:46:25;1685:33;;;1570:24;1685:33;;;:20;:33;;;;;;;;:47;;1750;;;;1815:48;;;;1881:56;;;;1955:42;;;;2015:51;;;;;1620:460;;-1:-1:-1;;;;;;1654:13:25;3855:3:31;3833:16;3829:51;1620:460:25;;;3817:64:31;;;;3897:11;;;3890:27;;;;3933:12;;;3926:28;;;;3970:12;;;3963:28;;;;4007:13;;;4000:29;;;;4045:13;;;4038:29;;;;4083:13;;;4076:29;;;;4121:13;;1620:460:25;;;;;;-1:-1:-1;;1620:460:25;;;;;;1597:493;;1620:460;1597:493;;;;2140:8;;2200:34;;;4274:19:31;;;1597:493:25;-1:-1:-1;;;;;;2140:8:25;;2128:38;;2180:6;;;;4309:12:31;2200:34:25;;;;;;;;;;;;2128:116;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2255:24:25;;;;;;;;:11;:24;;;;;:31;;-1:-1:-1;;2255:31:25;2282:4;2255:31;;;-1:-1:-1;;;;1396:897:25:o;1817:101:24:-;1087:13;:11;:13::i;:::-;1881:30:::1;1908:1;1881:18;:30::i;:::-;1817:101::o:0;2353:99:25:-;1087:13:24;:11;:13::i;:::-;2425:8:25::1;:20:::0;;-1:-1:-1;;;;;;2425:20:25::1;-1:-1:-1::0;;;;;2425:20:25;;;::::1;::::0;;;::::1;::::0;;2353:99::o;1157:177::-;1087:13:24;:11;:13::i;:::-;1281:33:25::1;::::0;::::1;;::::0;;;:20:::1;:33;::::0;;;;1317:10;;1281:46:::1;1317:10:::0;1281:33;5384:5:31;5371:19;5365:4;5358:33;5445:2;5438:5;5434:14;5421:28;5417:1;5411:4;5407:12;5400:50;5504:2;5497:5;5493:14;5480:28;5476:1;5470:4;5466:12;5459:50;5563:2;5556:5;5552:14;5539:28;5535:1;5529:4;5525:12;5518:50;5622:3;5615:5;5611:15;5598:29;5594:1;5588:4;5584:12;5577:51;5682:3;5675:5;5671:15;5658:29;5654:1;5648:4;5644:12;5637:51;;;5213:481;1281:46:25::1;-1:-1:-1::0;;;;1157:177:25:o;2067:198:24:-;1087:13;:11;:13::i;:::-;-1:-1:-1;;;;;2155:22:24;::::1;2147:73;;;::::0;-1:-1:-1;;;2147:73:24;;5901:2:31;2147:73:24::1;::::0;::::1;5883:21:31::0;5940:2;5920:18;;;5913:30;5979:34;5959:18;;;5952:62;-1:-1:-1;;;6030:18:31;;;6023:36;6076:19;;2147:73:24::1;5699:402:31::0;2147:73:24::1;2230:28;2249:8;2230:18;:28::i;:::-;2067:198:::0;:::o;1352:130::-;1240:7;1266:6;-1:-1:-1;;;;;1266:6:24;734:10:23;1415:23:24;1407:68;;;;-1:-1:-1;;;1407:68:24;;6308:2:31;1407:68:24;;;6290:21:31;;;6327:18;;;6320:30;6386:34;6366:18;;;6359:62;6438:18;;1407:68:24;6106:356:31;2419:187:24;2492:16;2511:6;;-1:-1:-1;;;;;2527:17:24;;;-1:-1:-1;;;;;;2527:17:24;;;;;;2559:40;;2511:6;;;;;;;2559:40;;2492:16;2559:40;2482:124;2419:187;:::o;219:180:31:-;278:6;331:2;319:9;310:7;306:23;302:32;299:52;;;347:1;344;337:12;299:52;-1:-1:-1;370:23:31;;219:180;-1:-1:-1;219:180:31:o;1344:171::-;1411:20;;1471:18;1460:30;;1450:41;;1440:69;;1505:1;1502;1495:12;1440:69;1344:171;;;:::o;1520:663::-;1598:6;1606;1614;1667:2;1655:9;1646:7;1642:23;1638:32;1635:52;;;1683:1;1680;1673:12;1635:52;1706:28;1724:9;1706:28;:::i;:::-;1696:38;;1785:2;1774:9;1770:18;1757:32;1808:18;1849:2;1841:6;1838:14;1835:34;;;1865:1;1862;1855:12;1835:34;1903:6;1892:9;1888:22;1878:32;;1948:7;1941:4;1937:2;1933:13;1929:27;1919:55;;1970:1;1967;1960:12;1919:55;2010:2;1997:16;2036:2;2028:6;2025:14;2022:34;;;2052:1;2049;2042:12;2022:34;2097:7;2092:2;2083:6;2079:2;2075:15;2071:24;2068:37;2065:57;;;2118:1;2115;2108:12;2065:57;2149:2;2145;2141:11;2131:21;;2171:6;2161:16;;;;;1520:663;;;;;:::o;2188:286::-;2247:6;2300:2;2288:9;2279:7;2275:23;2271:32;2268:52;;;2316:1;2313;2306:12;2268:52;2342:23;;-1:-1:-1;;;;;2394:31:31;;2384:42;;2374:70;;2440:1;2437;2430:12;2374:70;2463:5;2188:286;-1:-1:-1;;;2188:286:31:o;2479:346::-;2577:6;2585;2629:9;2620:7;2616:23;2659:3;2655:2;2651:12;2648:32;;;2676:1;2673;2666:12;2648:32;2699:28;2717:9;2699:28;:::i;:::-;2689:38;-1:-1:-1;2761:3:31;-1:-1:-1;;2743:16:31;;2739:26;2736:46;;;2778:1;2775;2768:12;2736:46;;2816:2;2805:9;2801:18;2791:28;;2479:346;;;;;:::o;4332:876::-;4535:2;4524:9;4517:21;4574:6;4569:2;4558:9;4554:18;4547:34;4631:6;4623;4618:2;4607:9;4603:18;4590:48;4687:1;4682:2;4673:6;4662:9;4658:22;4654:31;4647:42;4498:4;4712:2;4708:7;4770:2;4765;4757:6;4753:15;4749:24;4738:9;4734:40;4793:4;4859:2;4847:9;4843:2;4839:18;4835:27;4828:4;4817:9;4813:20;4806:57;4892:6;4886:13;4928:6;4923:2;4919;4915:11;4908:27;4953:1;4963:134;4977:6;4974:1;4971:13;4963:134;;;5066:14;;;5062:23;;5056:30;5038:10;;;5050:3;5034:20;5027:60;4992:10;;4963:134;;;4967:3;5140:1;5134:3;5125:6;5121:2;5117:15;5113:25;5106:36;5198:3;5192:2;5187;5179:6;5175:15;5171:24;5167:2;5163:33;5159:43;5151:51;;;;;;4332:876;;;;;;:::o", - "linkReferences": {}, - "immutableReferences": { - "40031": [ - { - "start": 179, - "length": 32 - }, - { - "start": 802, - "length": 32 - } - ] - } - }, - "methodIdentifiers": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": "9d049dda", - "committedBatchStores(uint256)": "0b79cdda", - "isProveSuccess(uint256)": "25684280", - "layer2ChainId()": "03c7f4af", - "owner()": "8da5cb5b", - "proveState(uint64,bytes)": "59ef1120", - "proveStatus(uint256)": "e7047c04", - "renounceOwnership()": "715018a6", - "transferOwnership(address)": "f2fde38b", - "updateVerifier(address)": "97fc007c", - "verifier()": "2b7ac3f3" - }, - "rawMetadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sequencerSetVerifyHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ShadowRollup.BatchStore\",\"name\":\"_batchData\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatchStores\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sequencerSetVerifyHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isProveSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"proveStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"params\":{\"_batchData\":\"The batch data\",\"_batchIndex\":\"The index of batch\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ShadowRollup\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"notice\":\"Commit a batch of transactions on layer 1.\"},\"layer2ChainId()\":{\"notice\":\"The chain id of the corresponding layer 2 chain.\"},\"updateVerifier(address)\":{\"notice\":\"Update the address verifier contract.\"},\"verifier()\":{\"notice\":\"The address of zkvm verifier.\"}},\"notice\":\"This contract maintains data for shadow rollup.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ShadowRollup.sol\":\"ShadowRollup\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/Context.sol\":{\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c\",\"dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h\"]},\"src/Ownable.sol\":{\"keccak256\":\"0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a\",\"dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB\"]},\"src/ShadowRollup.sol\":{\"keccak256\":\"0x7f2b4137ac3d0247c894349f6a3c43397a85e4fc46a52d527ef423f6952ffda9\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1a6e967d36f0f7b0a4c61c441314f19486f8f1288c2f61d1e2aa113001f8647a\",\"dweb:/ipfs/QmY2pZQAKL2QRDW746pmbvHegfLkYtbiShpXcqWNvXKARd\"]},\"src/libs/EvmVerifier.sol\":{\"keccak256\":\"0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2\",\"dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR\"]},\"src/libs/ISP1Verifier.sol\":{\"keccak256\":\"0xa2b12c98dab270cd8cf31437ed098fac584f46402c4a8a6abc4916762cf2f25a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://afaf82202de8cfa5931655d64736cb60f3fe4ea7e8de3f7783c8b7b5f64279a0\",\"dweb:/ipfs/QmSd2jcaJ3EZFLZyomhsDZVZqCeQaWWAwi5EUsE4fznB7d\"]},\"src/libs/PlonkVerifier.sol\":{\"keccak256\":\"0xd48c175491e3e69523ab78edce43662c44e6b3149b6aaca8689b5f11f1dbc7e4\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://d487e6c4270fd354d76217e50d979379cb3a19c31415a6af9fac63e8de06ef7e\",\"dweb:/ipfs/Qmcrr1pkQc6aoUGoX5sKoeQeXUH9b1T1p2Xyd3ZJUot4iX\"]},\"src/libs/SP1VerifierPlonk.sol\":{\"keccak256\":\"0xce6301ea7c14ca3756bb845316e4e25267ce3004f330f0b47e4ac07a39a0ab76\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://15cc4090f17e9d37478c4b49367d0b6fa466a3169c5431fc0aff76ba0a5f86f3\",\"dweb:/ipfs/QmWH1z6p2yeExs9yVA2p1b9X4WjFy3R9KJHKNghn7rmsWp\"]}},\"version\":1}", - "metadata": { - "compiler": { - "version": "0.8.24+commit.e11b9ed9" - }, - "language": "Solidity", - "output": { - "abi": [ - { - "inputs": [ - { - "internalType": "uint64", - "name": "_chainId", - "type": "uint64" - }, - { - "internalType": "address", - "name": "_verifier", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "previousOwner", - "type": "address", - "indexed": true - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address", - "indexed": true - } - ], - "type": "event", - "name": "OwnershipTransferred", - "anonymous": false - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_batchIndex", - "type": "uint64" - }, - { - "internalType": "struct ShadowRollup.BatchStore", - "name": "_batchData", - "type": "tuple", - "components": [ - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "sequencerSetVerifyHash", - "type": "bytes32" - } - ] - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "commitBatch" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "committedBatchStores", - "outputs": [ - { - "internalType": "bytes32", - "name": "prevStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "postStateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "withdrawalRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blobVersionedHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "sequencerSetVerifyHash", - "type": "bytes32" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_batchIndex", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "isProveSuccess", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "layer2ChainId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ] - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_batchIndex", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "_proof", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "proveState" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function", - "name": "proveStatus", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ] - }, - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "function", - "name": "renounceOwnership" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "transferOwnership" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_verifier", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function", - "name": "updateVerifier" - }, - { - "inputs": [], - "stateMutability": "view", - "type": "function", - "name": "verifier", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ] - } - ], - "devdoc": { - "kind": "dev", - "methods": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": { - "params": { - "_batchData": "The batch data", - "_batchIndex": "The index of batch" - } - }, - "owner()": { - "details": "Returns the address of the current owner." - }, - "renounceOwnership()": { - "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." - }, - "transferOwnership(address)": { - "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." - } - }, - "version": 1 - }, - "userdoc": { - "kind": "user", - "methods": { - "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32,bytes32))": { - "notice": "Commit a batch of transactions on layer 1." - }, - "layer2ChainId()": { - "notice": "The chain id of the corresponding layer 2 chain." - }, - "updateVerifier(address)": { - "notice": "Update the address verifier contract." - }, - "verifier()": { - "notice": "The address of zkvm verifier." - } - }, - "version": 1 - } - }, - "settings": { - "remappings": [ - "forge-std/=lib/forge-std/src/" - ], - "optimizer": { - "enabled": true, - "runs": 200 - }, - "metadata": { - "bytecodeHash": "ipfs" - }, - "compilationTarget": { - "src/ShadowRollup.sol": "ShadowRollup" - }, - "evmVersion": "paris", - "libraries": {} - }, - "sources": { - "src/Context.sol": { - "keccak256": "0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439", - "urls": [ - "bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c", - "dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h" - ], - "license": "MIT" - }, - "src/Ownable.sol": { - "keccak256": "0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8", - "urls": [ - "bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a", - "dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB" - ], - "license": "MIT" - }, - "src/ShadowRollup.sol": { - "keccak256": "0x7f2b4137ac3d0247c894349f6a3c43397a85e4fc46a52d527ef423f6952ffda9", - "urls": [ - "bzz-raw://1a6e967d36f0f7b0a4c61c441314f19486f8f1288c2f61d1e2aa113001f8647a", - "dweb:/ipfs/QmY2pZQAKL2QRDW746pmbvHegfLkYtbiShpXcqWNvXKARd" - ], - "license": "MIT" - }, - "src/libs/EvmVerifier.sol": { - "keccak256": "0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb", - "urls": [ - "bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2", - "dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR" - ], - "license": "MIT" - }, - "src/libs/ISP1Verifier.sol": { - "keccak256": "0xa2b12c98dab270cd8cf31437ed098fac584f46402c4a8a6abc4916762cf2f25a", - "urls": [ - "bzz-raw://afaf82202de8cfa5931655d64736cb60f3fe4ea7e8de3f7783c8b7b5f64279a0", - "dweb:/ipfs/QmSd2jcaJ3EZFLZyomhsDZVZqCeQaWWAwi5EUsE4fznB7d" - ], - "license": "MIT" - }, - "src/libs/PlonkVerifier.sol": { - "keccak256": "0xd48c175491e3e69523ab78edce43662c44e6b3149b6aaca8689b5f11f1dbc7e4", - "urls": [ - "bzz-raw://d487e6c4270fd354d76217e50d979379cb3a19c31415a6af9fac63e8de06ef7e", - "dweb:/ipfs/Qmcrr1pkQc6aoUGoX5sKoeQeXUH9b1T1p2Xyd3ZJUot4iX" - ], - "license": "Apache-2.0" - }, - "src/libs/SP1VerifierPlonk.sol": { - "keccak256": "0xce6301ea7c14ca3756bb845316e4e25267ce3004f330f0b47e4ac07a39a0ab76", - "urls": [ - "bzz-raw://15cc4090f17e9d37478c4b49367d0b6fa466a3169c5431fc0aff76ba0a5f86f3", - "dweb:/ipfs/QmWH1z6p2yeExs9yVA2p1b9X4WjFy3R9KJHKNghn7rmsWp" - ], - "license": "MIT" - } - }, - "version": 1 - }, - "id": 25 + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "_chainId", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_verifier", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "commitBatch", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_batchData", + "type": "tuple", + "internalType": "struct ShadowRollup.BatchStore", + "components": [ + { + "name": "prevStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "postStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "withdrawalRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "blobVersionedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "committedBatchStores", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "prevStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "postStateRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "withdrawalRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "dataHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "blobVersionedHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isProveSuccess", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "layer2ChainId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint64", + "internalType": "uint64" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proveState", + "inputs": [ + { + "name": "_batchIndex", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "_proof", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "proveStatus", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "updateVerifier", + "inputs": [ + { + "name": "_verifier", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifier", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } + ], + "bytecode": { + "object": "0x60a060405234801562000010575f80fd5b50604051620012dc380380620012dc833981810160405281019062000036919062000229565b620000566200004a620000ba60201b60201c565b620000c160201b60201c565b8167ffffffffffffffff1660808167ffffffffffffffff16815250508060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506200026e565b5f33905090565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f80fd5b5f67ffffffffffffffff82169050919050565b620001a48162000186565b8114620001af575f80fd5b50565b5f81519050620001c28162000199565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620001f382620001c8565b9050919050565b6200020581620001e7565b811462000210575f80fd5b50565b5f815190506200022381620001fa565b92915050565b5f806040838503121562000242576200024162000182565b5b5f6200025185828601620001b2565b9250506020620002648582860162000213565b9150509250929050565b60805161104e6200028e5f395f8181610215015261033e015261104e5ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063715018a61161006f578063715018a6146101675780638da5cb5b1461017157806397fc007c1461018f578063d181ed76146101ab578063e7047c04146101c7578063f2fde38b146101f7576100a7565b806303c7f4af146100ab5780630b79cdda146100c957806325684280146100fd5780632b7ac3f31461012d57806359ef11201461014b575b5f80fd5b6100b3610213565b6040516100c091906107cd565b60405180910390f35b6100e360048036038101906100de9190610821565b610237565b6040516100f4959493929190610864565b60405180910390f35b61011760048036038101906101129190610821565b610269565b60405161012491906108cf565b60405180910390f35b6101356102d1565b6040516101429190610927565b60405180910390f35b610165600480360381019061016091906109cb565b6102f6565b005b61016f61050a565b005b61017961051d565b6040516101869190610927565b60405180910390f35b6101a960048036038101906101a49190610a52565b610544565b005b6101c560048036038101906101c09190610a9f565b61058f565b005b6101e160048036038101906101dc9190610821565b6105c6565b6040516101ee91906108cf565b60405180910390f35b610211600480360381019061020c9190610a52565b6105e3565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b6002602052805f5260405f205f91509050805f0154908060010154908060020154908060030154908060040154905085565b5f8082116102ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a390610b37565b60405180910390fd5b60035f8381526020019081526020015f205f9054906101000a900460ff169050919050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f828290501161033b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033290610b9f565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000060025f8667ffffffffffffffff1681526020019081526020015f205f015460025f8767ffffffffffffffff1681526020019081526020015f206001015460025f8867ffffffffffffffff1681526020019081526020015f20600201545f801b60025f8a67ffffffffffffffff1681526020019081526020015f206003015460025f8b67ffffffffffffffff1681526020019081526020015f20600401546040516020016104109796959493929190610c11565b60405160208183030381529060405280519060200120905060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b768f1c98484846040516020016104789190610c91565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016104a593929190610d6f565b5f6040518083038186803b1580156104bb575f80fd5b505afa1580156104cd573d5f803e3d5ffd5b50505050600160035f8667ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050505050565b610512610665565b61051b5f6106e3565b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054c610665565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610597610665565b8060025f8467ffffffffffffffff1681526020019081526020015f2081816105bf9190610f14565b9050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6105eb610665565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610659576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065090610f92565b60405180910390fd5b610662816106e3565b50565b61066d6107a4565b73ffffffffffffffffffffffffffffffffffffffff1661068b61051d565b73ffffffffffffffffffffffffffffffffffffffff16146106e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d890610ffa565b60405180910390fd5b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f33905090565b5f67ffffffffffffffff82169050919050565b6107c7816107ab565b82525050565b5f6020820190506107e05f8301846107be565b92915050565b5f80fd5b5f80fd5b5f819050919050565b610800816107ee565b811461080a575f80fd5b50565b5f8135905061081b816107f7565b92915050565b5f60208284031215610836576108356107e6565b5b5f6108438482850161080d565b91505092915050565b5f819050919050565b61085e8161084c565b82525050565b5f60a0820190506108775f830188610855565b6108846020830187610855565b6108916040830186610855565b61089e6060830185610855565b6108ab6080830184610855565b9695505050505050565b5f8115159050919050565b6108c9816108b5565b82525050565b5f6020820190506108e25f8301846108c0565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610911826108e8565b9050919050565b61092181610907565b82525050565b5f60208201905061093a5f830184610918565b92915050565b610949816107ab565b8114610953575f80fd5b50565b5f8135905061096481610940565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261098b5761098a61096a565b5b8235905067ffffffffffffffff8111156109a8576109a761096e565b5b6020830191508360018202830111156109c4576109c3610972565b5b9250929050565b5f805f604084860312156109e2576109e16107e6565b5b5f6109ef86828701610956565b935050602084013567ffffffffffffffff811115610a1057610a0f6107ea565b5b610a1c86828701610976565b92509250509250925092565b610a3181610907565b8114610a3b575f80fd5b50565b5f81359050610a4c81610a28565b92915050565b5f60208284031215610a6757610a666107e6565b5b5f610a7484828501610a3e565b91505092915050565b5f80fd5b5f60a08284031215610a9657610a95610a7d565b5b81905092915050565b5f8060c08385031215610ab557610ab46107e6565b5b5f610ac285828601610956565b9250506020610ad385828601610a81565b9150509250929050565b5f82825260208201905092915050565b7f696e76616c6964206261746368496e64657800000000000000000000000000005f82015250565b5f610b21601283610add565b9150610b2c82610aed565b602082019050919050565b5f6020820190508181035f830152610b4e81610b15565b9050919050565b7f496e76616c6964207a6b2070726f6f66000000000000000000000000000000005f82015250565b5f610b89601083610add565b9150610b9482610b55565b602082019050919050565b5f6020820190508181035f830152610bb681610b7d565b9050919050565b5f8160c01b9050919050565b5f610bd382610bbd565b9050919050565b610beb610be6826107ab565b610bc9565b82525050565b5f819050919050565b610c0b610c068261084c565b610bf1565b82525050565b5f610c1c828a610bda565b600882019150610c2c8289610bfa565b602082019150610c3c8288610bfa565b602082019150610c4c8287610bfa565b602082019150610c5c8286610bfa565b602082019150610c6c8285610bfa565b602082019150610c7c8284610bfa565b60208201915081905098975050505050505050565b5f610c9c8284610bfa565b60208201915081905092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f610ce48385610cab565b9350610cf1838584610cbb565b610cfa83610cc9565b840190509392505050565b5f81519050919050565b5f5b83811015610d2c578082015181840152602081019050610d11565b5f8484015250505050565b5f610d4182610d05565b610d4b8185610cab565b9350610d5b818560208601610d0f565b610d6481610cc9565b840191505092915050565b5f6040820190508181035f830152610d88818587610cd9565b90508181036020830152610d9c8184610d37565b9050949350505050565b610daf8161084c565b8114610db9575f80fd5b50565b5f8135610dc881610da6565b80915050919050565b5f815f1b9050919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610e0784610dd1565b9350801983169250808416831791505092915050565b5f610e278261084c565b9050919050565b5f815f1c9050919050565b5f610e4382610e2e565b9050919050565b610e5382610e1d565b610e66610e5f82610e39565b8354610ddc565b8255505050565b5f81015f830180610e7d81610dbc565b9050610e898184610e4a565b505050600181016020830180610e9e81610dbc565b9050610eaa8184610e4a565b505050600281016040830180610ebf81610dbc565b9050610ecb8184610e4a565b505050600381016060830180610ee081610dbc565b9050610eec8184610e4a565b505050600481016080830180610f0181610dbc565b9050610f0d8184610e4a565b5050505050565b610f1e8282610e6d565b5050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b5f610f7c602683610add565b9150610f8782610f22565b604082019050919050565b5f6020820190508181035f830152610fa981610f70565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f82015250565b5f610fe4602083610add565b9150610fef82610fb0565b602082019050919050565b5f6020820190508181035f83015261101181610fd8565b905091905056fea2646970667358221220e56002070fb4c68e802e5ce65eb8314d43691042bf73f4658dd277afa9b08e5564736f6c63430008180033", + "sourceMap": "219:2276:21:-:0;;;837:119;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;929:32:20;948:12;:10;;;:12;;:::i;:::-;929:18;;;:32;;:::i;:::-;911:8:21;895:24;;;;;;;;;;940:9;929:8;;:20;;;;;;;;;;;;;;;;;;837:119;;219:2276;;655:96:19;708:7;734:10;727:17;;655:96;:::o;2419:187:20:-;2492:16;2511:6;;;;;;;;;;;2492:25;;2536:8;2527:6;;:17;;;;;;;;;;;;;;;;;;2590:8;2559:40;;2580:8;2559:40;;;;;;;;;;;;2482:124;2419:187;:::o;88:117:27:-;197:1;194;187:12;334:101;370:7;410:18;403:5;399:30;388:41;;334:101;;;:::o;441:120::-;513:23;530:5;513:23;:::i;:::-;506:5;503:34;493:62;;551:1;548;541:12;493:62;441:120;:::o;567:141::-;623:5;654:6;648:13;639:22;;670:32;696:5;670:32;:::i;:::-;567:141;;;;:::o;714:126::-;751:7;791:42;784:5;780:54;769:65;;714:126;;;:::o;846:96::-;883:7;912:24;930:5;912:24;:::i;:::-;901:35;;846:96;;;:::o;948:122::-;1021:24;1039:5;1021:24;:::i;:::-;1014:5;1011:35;1001:63;;1060:1;1057;1050:12;1001:63;948:122;:::o;1076:143::-;1133:5;1164:6;1158:13;1149:22;;1180:33;1207:5;1180:33;:::i;:::-;1076:143;;;;:::o;1225:505::-;1303:6;1311;1360:2;1348:9;1339:7;1335:23;1331:32;1328:119;;;1366:79;;:::i;:::-;1328:119;1486:1;1511:63;1566:7;1557:6;1546:9;1542:22;1511:63;:::i;:::-;1501:73;;1457:127;1623:2;1649:64;1705:7;1696:6;1685:9;1681:22;1649:64;:::i;:::-;1639:74;;1594:129;1225:505;;;;;:::o;219:2276:21:-;;;;;;;;;;;;;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063715018a61161006f578063715018a6146101675780638da5cb5b1461017157806397fc007c1461018f578063d181ed76146101ab578063e7047c04146101c7578063f2fde38b146101f7576100a7565b806303c7f4af146100ab5780630b79cdda146100c957806325684280146100fd5780632b7ac3f31461012d57806359ef11201461014b575b5f80fd5b6100b3610213565b6040516100c091906107cd565b60405180910390f35b6100e360048036038101906100de9190610821565b610237565b6040516100f4959493929190610864565b60405180910390f35b61011760048036038101906101129190610821565b610269565b60405161012491906108cf565b60405180910390f35b6101356102d1565b6040516101429190610927565b60405180910390f35b610165600480360381019061016091906109cb565b6102f6565b005b61016f61050a565b005b61017961051d565b6040516101869190610927565b60405180910390f35b6101a960048036038101906101a49190610a52565b610544565b005b6101c560048036038101906101c09190610a9f565b61058f565b005b6101e160048036038101906101dc9190610821565b6105c6565b6040516101ee91906108cf565b60405180910390f35b610211600480360381019061020c9190610a52565b6105e3565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b6002602052805f5260405f205f91509050805f0154908060010154908060020154908060030154908060040154905085565b5f8082116102ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a390610b37565b60405180910390fd5b60035f8381526020019081526020015f205f9054906101000a900460ff169050919050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f828290501161033b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161033290610b9f565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000060025f8667ffffffffffffffff1681526020019081526020015f205f015460025f8767ffffffffffffffff1681526020019081526020015f206001015460025f8867ffffffffffffffff1681526020019081526020015f20600201545f801b60025f8a67ffffffffffffffff1681526020019081526020015f206003015460025f8b67ffffffffffffffff1681526020019081526020015f20600401546040516020016104109796959493929190610c11565b60405160208183030381529060405280519060200120905060015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b768f1c98484846040516020016104789190610c91565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016104a593929190610d6f565b5f6040518083038186803b1580156104bb575f80fd5b505afa1580156104cd573d5f803e3d5ffd5b50505050600160035f8667ffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555050505050565b610512610665565b61051b5f6106e3565b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b61054c610665565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610597610665565b8060025f8467ffffffffffffffff1681526020019081526020015f2081816105bf9190610f14565b9050505050565b6003602052805f5260405f205f915054906101000a900460ff1681565b6105eb610665565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610659576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065090610f92565b60405180910390fd5b610662816106e3565b50565b61066d6107a4565b73ffffffffffffffffffffffffffffffffffffffff1661068b61051d565b73ffffffffffffffffffffffffffffffffffffffff16146106e1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d890610ffa565b60405180910390fd5b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f33905090565b5f67ffffffffffffffff82169050919050565b6107c7816107ab565b82525050565b5f6020820190506107e05f8301846107be565b92915050565b5f80fd5b5f80fd5b5f819050919050565b610800816107ee565b811461080a575f80fd5b50565b5f8135905061081b816107f7565b92915050565b5f60208284031215610836576108356107e6565b5b5f6108438482850161080d565b91505092915050565b5f819050919050565b61085e8161084c565b82525050565b5f60a0820190506108775f830188610855565b6108846020830187610855565b6108916040830186610855565b61089e6060830185610855565b6108ab6080830184610855565b9695505050505050565b5f8115159050919050565b6108c9816108b5565b82525050565b5f6020820190506108e25f8301846108c0565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610911826108e8565b9050919050565b61092181610907565b82525050565b5f60208201905061093a5f830184610918565b92915050565b610949816107ab565b8114610953575f80fd5b50565b5f8135905061096481610940565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261098b5761098a61096a565b5b8235905067ffffffffffffffff8111156109a8576109a761096e565b5b6020830191508360018202830111156109c4576109c3610972565b5b9250929050565b5f805f604084860312156109e2576109e16107e6565b5b5f6109ef86828701610956565b935050602084013567ffffffffffffffff811115610a1057610a0f6107ea565b5b610a1c86828701610976565b92509250509250925092565b610a3181610907565b8114610a3b575f80fd5b50565b5f81359050610a4c81610a28565b92915050565b5f60208284031215610a6757610a666107e6565b5b5f610a7484828501610a3e565b91505092915050565b5f80fd5b5f60a08284031215610a9657610a95610a7d565b5b81905092915050565b5f8060c08385031215610ab557610ab46107e6565b5b5f610ac285828601610956565b9250506020610ad385828601610a81565b9150509250929050565b5f82825260208201905092915050565b7f696e76616c6964206261746368496e64657800000000000000000000000000005f82015250565b5f610b21601283610add565b9150610b2c82610aed565b602082019050919050565b5f6020820190508181035f830152610b4e81610b15565b9050919050565b7f496e76616c6964207a6b2070726f6f66000000000000000000000000000000005f82015250565b5f610b89601083610add565b9150610b9482610b55565b602082019050919050565b5f6020820190508181035f830152610bb681610b7d565b9050919050565b5f8160c01b9050919050565b5f610bd382610bbd565b9050919050565b610beb610be6826107ab565b610bc9565b82525050565b5f819050919050565b610c0b610c068261084c565b610bf1565b82525050565b5f610c1c828a610bda565b600882019150610c2c8289610bfa565b602082019150610c3c8288610bfa565b602082019150610c4c8287610bfa565b602082019150610c5c8286610bfa565b602082019150610c6c8285610bfa565b602082019150610c7c8284610bfa565b60208201915081905098975050505050505050565b5f610c9c8284610bfa565b60208201915081905092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f610ce48385610cab565b9350610cf1838584610cbb565b610cfa83610cc9565b840190509392505050565b5f81519050919050565b5f5b83811015610d2c578082015181840152602081019050610d11565b5f8484015250505050565b5f610d4182610d05565b610d4b8185610cab565b9350610d5b818560208601610d0f565b610d6481610cc9565b840191505092915050565b5f6040820190508181035f830152610d88818587610cd9565b90508181036020830152610d9c8184610d37565b9050949350505050565b610daf8161084c565b8114610db9575f80fd5b50565b5f8135610dc881610da6565b80915050919050565b5f815f1b9050919050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610e0784610dd1565b9350801983169250808416831791505092915050565b5f610e278261084c565b9050919050565b5f815f1c9050919050565b5f610e4382610e2e565b9050919050565b610e5382610e1d565b610e66610e5f82610e39565b8354610ddc565b8255505050565b5f81015f830180610e7d81610dbc565b9050610e898184610e4a565b505050600181016020830180610e9e81610dbc565b9050610eaa8184610e4a565b505050600281016040830180610ebf81610dbc565b9050610ecb8184610e4a565b505050600381016060830180610ee081610dbc565b9050610eec8184610e4a565b505050600481016080830180610f0181610dbc565b9050610f0d8184610e4a565b5050505050565b610f1e8282610e6d565b5050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b5f610f7c602683610add565b9150610f8782610f22565b604082019050919050565b5f6020820190508181035f830152610fa981610f70565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725f82015250565b5f610fe4602083610add565b9150610fef82610fb0565b602082019050919050565b5f6020820190508181035f83015261101181610fd8565b905091905056fea2646970667358221220e56002070fb4c68e802e5ce65eb8314d43691042bf73f4658dd277afa9b08e5564736f6c63430008180033", + "sourceMap": "219:2276:21:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;323:37;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;629:58;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;2315:178;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;413:23;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1333:817;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1817:101:20;;;:::i;:::-;;1194:85;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2210:99:21;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1116:155;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;722:43;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2067:198:20;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;323:37:21;;;:::o;629:58::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;2315:178::-;2383:4;2421:1;2407:11;:15;2399:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;2462:11;:24;2474:11;2462:24;;;;;;;;;;;;;;;;;;;;;2455:31;;2315:178;;;:::o;413:23::-;;;;;;;;;;;;;:::o;1333:817::-;1474:1;1458:6;;:13;;:17;1450:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;1507:24;1591:13;1622:20;:33;1643:11;1622:33;;;;;;;;;;;;;:47;;;1687:20;:33;1708:11;1687:33;;;;;;;;;;;;;:47;;;1752:20;:33;1773:11;1752:33;;;;;;;;;;;;;:48;;;1826:1;1818:10;;1846:20;:33;1867:11;1846:33;;;;;;;;;;;;;:42;;;1906:20;:33;1927:11;1906:33;;;;;;;;;;;;;:51;;;1557:414;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1534:447;;;;;;1507:474;;2031:8;;;;;;;;;;;2019:38;;;2058:6;;2083:16;2066:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;2019:82;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2139:4;2112:11;:24;2124:11;2112:24;;;;;;;;;;;;;;:31;;;;;;;;;;;;;;;;;;1405:745;1333:817;;;:::o;1817:101:20:-;1087:13;:11;:13::i;:::-;1881:30:::1;1908:1;1881:18;:30::i;:::-;1817:101::o:0;1194:85::-;1240:7;1266:6;;;;;;;;;;;1259:13;;1194:85;:::o;2210:99:21:-;1087:13:20;:11;:13::i;:::-;2293:9:21::1;2282:8;;:20;;;;;;;;;;;;;;;;;;2210:99:::0;:::o;1116:155::-;1087:13:20;:11;:13::i;:::-;1254:10:21::1;1218:20;:33;1239:11;1218:33;;;;;;;;;;;;;:46;;;;;;:::i;:::-;;;;1116:155:::0;;:::o;722:43::-;;;;;;;;;;;;;;;;;;;;;;:::o;2067:198:20:-;1087:13;:11;:13::i;:::-;2175:1:::1;2155:22;;:8;:22;;::::0;2147:73:::1;;;;;;;;;;;;:::i;:::-;;;;;;;;;2230:28;2249:8;2230:18;:28::i;:::-;2067:198:::0;:::o;1352:130::-;1426:12;:10;:12::i;:::-;1415:23;;:7;:5;:7::i;:::-;:23;;;1407:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;1352:130::o;2419:187::-;2492:16;2511:6;;;;;;;;;;;2492:25;;2536:8;2527:6;;:17;;;;;;;;;;;;;;;;;;2590:8;2559:40;;2580:8;2559:40;;;;;;;;;;;;2482:124;2419:187;:::o;655:96:19:-;708:7;734:10;727:17;;655:96;:::o;7:101:27:-;43:7;83:18;76:5;72:30;61:41;;7:101;;;:::o;114:115::-;199:23;216:5;199:23;:::i;:::-;194:3;187:36;114:115;;:::o;235:218::-;326:4;364:2;353:9;349:18;341:26;;377:69;443:1;432:9;428:17;419:6;377:69;:::i;:::-;235:218;;;;:::o;540:117::-;649:1;646;639:12;663:117;772:1;769;762:12;786:77;823:7;852:5;841:16;;786:77;;;:::o;869:122::-;942:24;960:5;942:24;:::i;:::-;935:5;932:35;922:63;;981:1;978;971:12;922:63;869:122;:::o;997:139::-;1043:5;1081:6;1068:20;1059:29;;1097:33;1124:5;1097:33;:::i;:::-;997:139;;;;:::o;1142:329::-;1201:6;1250:2;1238:9;1229:7;1225:23;1221:32;1218:119;;;1256:79;;:::i;:::-;1218:119;1376:1;1401:53;1446:7;1437:6;1426:9;1422:22;1401:53;:::i;:::-;1391:63;;1347:117;1142:329;;;;:::o;1477:77::-;1514:7;1543:5;1532:16;;1477:77;;;:::o;1560:118::-;1647:24;1665:5;1647:24;:::i;:::-;1642:3;1635:37;1560:118;;:::o;1684:664::-;1889:4;1927:3;1916:9;1912:19;1904:27;;1941:71;2009:1;1998:9;1994:17;1985:6;1941:71;:::i;:::-;2022:72;2090:2;2079:9;2075:18;2066:6;2022:72;:::i;:::-;2104;2172:2;2161:9;2157:18;2148:6;2104:72;:::i;:::-;2186;2254:2;2243:9;2239:18;2230:6;2186:72;:::i;:::-;2268:73;2336:3;2325:9;2321:19;2312:6;2268:73;:::i;:::-;1684:664;;;;;;;;:::o;2354:90::-;2388:7;2431:5;2424:13;2417:21;2406:32;;2354:90;;;:::o;2450:109::-;2531:21;2546:5;2531:21;:::i;:::-;2526:3;2519:34;2450:109;;:::o;2565:210::-;2652:4;2690:2;2679:9;2675:18;2667:26;;2703:65;2765:1;2754:9;2750:17;2741:6;2703:65;:::i;:::-;2565:210;;;;:::o;2781:126::-;2818:7;2858:42;2851:5;2847:54;2836:65;;2781:126;;;:::o;2913:96::-;2950:7;2979:24;2997:5;2979:24;:::i;:::-;2968:35;;2913:96;;;:::o;3015:118::-;3102:24;3120:5;3102:24;:::i;:::-;3097:3;3090:37;3015:118;;:::o;3139:222::-;3232:4;3270:2;3259:9;3255:18;3247:26;;3283:71;3351:1;3340:9;3336:17;3327:6;3283:71;:::i;:::-;3139:222;;;;:::o;3367:120::-;3439:23;3456:5;3439:23;:::i;:::-;3432:5;3429:34;3419:62;;3477:1;3474;3467:12;3419:62;3367:120;:::o;3493:137::-;3538:5;3576:6;3563:20;3554:29;;3592:32;3618:5;3592:32;:::i;:::-;3493:137;;;;:::o;3636:117::-;3745:1;3742;3735:12;3759:117;3868:1;3865;3858:12;3882:117;3991:1;3988;3981:12;4018:552;4075:8;4085:6;4135:3;4128:4;4120:6;4116:17;4112:27;4102:122;;4143:79;;:::i;:::-;4102:122;4256:6;4243:20;4233:30;;4286:18;4278:6;4275:30;4272:117;;;4308:79;;:::i;:::-;4272:117;4422:4;4414:6;4410:17;4398:29;;4476:3;4468:4;4460:6;4456:17;4446:8;4442:32;4439:41;4436:128;;;4483:79;;:::i;:::-;4436:128;4018:552;;;;;:::o;4576:670::-;4654:6;4662;4670;4719:2;4707:9;4698:7;4694:23;4690:32;4687:119;;;4725:79;;:::i;:::-;4687:119;4845:1;4870:52;4914:7;4905:6;4894:9;4890:22;4870:52;:::i;:::-;4860:62;;4816:116;4999:2;4988:9;4984:18;4971:32;5030:18;5022:6;5019:30;5016:117;;;5052:79;;:::i;:::-;5016:117;5165:64;5221:7;5212:6;5201:9;5197:22;5165:64;:::i;:::-;5147:82;;;;4942:297;4576:670;;;;;:::o;5252:122::-;5325:24;5343:5;5325:24;:::i;:::-;5318:5;5315:35;5305:63;;5364:1;5361;5354:12;5305:63;5252:122;:::o;5380:139::-;5426:5;5464:6;5451:20;5442:29;;5480:33;5507:5;5480:33;:::i;:::-;5380:139;;;;:::o;5525:329::-;5584:6;5633:2;5621:9;5612:7;5608:23;5604:32;5601:119;;;5639:79;;:::i;:::-;5601:119;5759:1;5784:53;5829:7;5820:6;5809:9;5805:22;5784:53;:::i;:::-;5774:63;;5730:117;5525:329;;;;:::o;5860:117::-;5969:1;5966;5959:12;6021:236;6098:5;6139:3;6130:6;6125:3;6121:16;6117:26;6114:113;;;6146:79;;:::i;:::-;6114:113;6245:6;6236:15;;6021:236;;;;:::o;6263:535::-;6361:6;6369;6418:3;6406:9;6397:7;6393:23;6389:33;6386:120;;;6425:79;;:::i;:::-;6386:120;6545:1;6570:52;6614:7;6605:6;6594:9;6590:22;6570:52;:::i;:::-;6560:62;;6516:116;6671:2;6697:84;6773:7;6764:6;6753:9;6749:22;6697:84;:::i;:::-;6687:94;;6642:149;6263:535;;;;;:::o;6804:169::-;6888:11;6922:6;6917:3;6910:19;6962:4;6957:3;6953:14;6938:29;;6804:169;;;;:::o;6979:168::-;7119:20;7115:1;7107:6;7103:14;7096:44;6979:168;:::o;7153:366::-;7295:3;7316:67;7380:2;7375:3;7316:67;:::i;:::-;7309:74;;7392:93;7481:3;7392:93;:::i;:::-;7510:2;7505:3;7501:12;7494:19;;7153:366;;;:::o;7525:419::-;7691:4;7729:2;7718:9;7714:18;7706:26;;7778:9;7772:4;7768:20;7764:1;7753:9;7749:17;7742:47;7806:131;7932:4;7806:131;:::i;:::-;7798:139;;7525:419;;;:::o;7950:166::-;8090:18;8086:1;8078:6;8074:14;8067:42;7950:166;:::o;8122:366::-;8264:3;8285:67;8349:2;8344:3;8285:67;:::i;:::-;8278:74;;8361:93;8450:3;8361:93;:::i;:::-;8479:2;8474:3;8470:12;8463:19;;8122:366;;;:::o;8494:419::-;8660:4;8698:2;8687:9;8683:18;8675:26;;8747:9;8741:4;8737:20;8733:1;8722:9;8718:17;8711:47;8775:131;8901:4;8775:131;:::i;:::-;8767:139;;8494:419;;;:::o;8919:96::-;8953:8;9002:5;8997:3;8993:15;8972:36;;8919:96;;;:::o;9021:94::-;9059:7;9088:21;9103:5;9088:21;:::i;:::-;9077:32;;9021:94;;;:::o;9121:153::-;9224:43;9243:23;9260:5;9243:23;:::i;:::-;9224:43;:::i;:::-;9219:3;9212:56;9121:153;;:::o;9280:79::-;9319:7;9348:5;9337:16;;9280:79;;;:::o;9365:157::-;9470:45;9490:24;9508:5;9490:24;:::i;:::-;9470:45;:::i;:::-;9465:3;9458:58;9365:157;;:::o;9528:1097::-;9806:3;9821:73;9890:3;9881:6;9821:73;:::i;:::-;9919:1;9914:3;9910:11;9903:18;;9931:75;10002:3;9993:6;9931:75;:::i;:::-;10031:2;10026:3;10022:12;10015:19;;10044:75;10115:3;10106:6;10044:75;:::i;:::-;10144:2;10139:3;10135:12;10128:19;;10157:75;10228:3;10219:6;10157:75;:::i;:::-;10257:2;10252:3;10248:12;10241:19;;10270:75;10341:3;10332:6;10270:75;:::i;:::-;10370:2;10365:3;10361:12;10354:19;;10383:75;10454:3;10445:6;10383:75;:::i;:::-;10483:2;10478:3;10474:12;10467:19;;10496:75;10567:3;10558:6;10496:75;:::i;:::-;10596:2;10591:3;10587:12;10580:19;;10616:3;10609:10;;9528:1097;;;;;;;;;;:::o;10631:256::-;10743:3;10758:75;10829:3;10820:6;10758:75;:::i;:::-;10858:2;10853:3;10849:12;10842:19;;10878:3;10871:10;;10631:256;;;;:::o;10893:168::-;10976:11;11010:6;11005:3;10998:19;11050:4;11045:3;11041:14;11026:29;;10893:168;;;;:::o;11067:146::-;11164:6;11159:3;11154;11141:30;11205:1;11196:6;11191:3;11187:16;11180:27;11067:146;;;:::o;11219:102::-;11260:6;11311:2;11307:7;11302:2;11295:5;11291:14;11287:28;11277:38;;11219:102;;;:::o;11349:314::-;11445:3;11466:70;11529:6;11524:3;11466:70;:::i;:::-;11459:77;;11546:56;11595:6;11590:3;11583:5;11546:56;:::i;:::-;11627:29;11649:6;11627:29;:::i;:::-;11622:3;11618:39;11611:46;;11349:314;;;;;:::o;11669:98::-;11720:6;11754:5;11748:12;11738:22;;11669:98;;;:::o;11773:246::-;11854:1;11864:113;11878:6;11875:1;11872:13;11864:113;;;11963:1;11958:3;11954:11;11948:18;11944:1;11939:3;11935:11;11928:39;11900:2;11897:1;11893:10;11888:15;;11864:113;;;12011:1;12002:6;11997:3;11993:16;11986:27;11835:184;11773:246;;;:::o;12025:373::-;12111:3;12139:38;12171:5;12139:38;:::i;:::-;12193:70;12256:6;12251:3;12193:70;:::i;:::-;12186:77;;12272:65;12330:6;12325:3;12318:4;12311:5;12307:16;12272:65;:::i;:::-;12362:29;12384:6;12362:29;:::i;:::-;12357:3;12353:39;12346:46;;12115:283;12025:373;;;;:::o;12404:526::-;12571:4;12609:2;12598:9;12594:18;12586:26;;12658:9;12652:4;12648:20;12644:1;12633:9;12629:17;12622:47;12686:86;12767:4;12758:6;12750;12686:86;:::i;:::-;12678:94;;12819:9;12813:4;12809:20;12804:2;12793:9;12789:18;12782:48;12847:76;12918:4;12909:6;12847:76;:::i;:::-;12839:84;;12404:526;;;;;;:::o;13122:122::-;13195:24;13213:5;13195:24;:::i;:::-;13188:5;13185:35;13175:63;;13234:1;13231;13224:12;13175:63;13122:122;:::o;13250:186::-;13295:11;13344:3;13331:17;13357:33;13384:5;13357:33;:::i;:::-;13424:5;13400:29;;13307:129;13250:186;;;:::o;13442:92::-;13474:8;13521:5;13518:1;13514:13;13493:34;;13442:92;;;:::o;13540:290::-;13598:6;13627:66;13714:22;13727:8;13714:22;:::i;:::-;13702:34;;13769:4;13765:9;13758:5;13754:21;13745:30;;13818:4;13808:8;13804:19;13797:5;13794:30;13784:40;;13605:225;13540:290;;;;:::o;13836:113::-;13886:9;13919:24;13937:5;13919:24;:::i;:::-;13906:37;;13836:113;;;:::o;13955:102::-;13997:8;14044:5;14041:1;14037:13;14016:34;;13955:102;;;:::o;14063:99::-;14106:3;14127:29;14150:5;14127:29;:::i;:::-;14120:36;;14063:99;;;:::o;14168:262::-;14278:39;14309:7;14278:39;:::i;:::-;14339:84;14381:41;14405:16;14381:41;:::i;:::-;14374:4;14368:11;14339:84;:::i;:::-;14333:4;14326:98;14244:186;14168:262;;:::o;14436:1828::-;14620:1;14614:4;14610:12;14666:1;14659:5;14655:13;14716:12;14759:42;14787:13;14759:42;:::i;:::-;14742:59;;14815:78;14879:13;14867:10;14815:78;:::i;:::-;14577:327;;;14957:1;14951:4;14947:12;15003:2;14996:5;14992:14;15054:12;15097:42;15125:13;15097:42;:::i;:::-;15080:59;;15153:78;15217:13;15205:10;15153:78;:::i;:::-;14914:328;;;15295:1;15289:4;15285:12;15341:2;15334:5;15330:14;15392:12;15435:42;15463:13;15435:42;:::i;:::-;15418:59;;15491:78;15555:13;15543:10;15491:78;:::i;:::-;15252:328;;;15633:1;15627:4;15623:12;15679:2;15672:5;15668:14;15730:12;15773:42;15801:13;15773:42;:::i;:::-;15756:59;;15829:78;15893:13;15881:10;15829:78;:::i;:::-;15590:328;;;15971:1;15965:4;15961:12;16017:3;16010:5;16006:15;16069:12;16112:42;16140:13;16112:42;:::i;:::-;16095:59;;16168:78;16232:13;16220:10;16168:78;:::i;:::-;15928:329;;;14436:1828;;:::o;16270:272::-;16414:122;16528:7;16522:4;16414:122;:::i;:::-;16270:272;;:::o;16548:225::-;16688:34;16684:1;16676:6;16672:14;16665:58;16757:8;16752:2;16744:6;16740:15;16733:33;16548:225;:::o;16779:366::-;16921:3;16942:67;17006:2;17001:3;16942:67;:::i;:::-;16935:74;;17018:93;17107:3;17018:93;:::i;:::-;17136:2;17131:3;17127:12;17120:19;;16779:366;;;:::o;17151:419::-;17317:4;17355:2;17344:9;17340:18;17332:26;;17404:9;17398:4;17394:20;17390:1;17379:9;17375:17;17368:47;17432:131;17558:4;17432:131;:::i;:::-;17424:139;;17151:419;;;:::o;17576:182::-;17716:34;17712:1;17704:6;17700:14;17693:58;17576:182;:::o;17764:366::-;17906:3;17927:67;17991:2;17986:3;17927:67;:::i;:::-;17920:74;;18003:93;18092:3;18003:93;:::i;:::-;18121:2;18116:3;18112:12;18105:19;;17764:366;;;:::o;18136:419::-;18302:4;18340:2;18329:9;18325:18;18317:26;;18389:9;18383:4;18379:20;18375:1;18364:9;18360:17;18353:47;18417:131;18543:4;18417:131;:::i;:::-;18409:139;;18136:419;;;:::o", + "linkReferences": {}, + "immutableReferences": { + "41510": [ + { + "start": 533, + "length": 32 + }, + { + "start": 830, + "length": 32 + } + ] + } + }, + "methodIdentifiers": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": "d181ed76", + "committedBatchStores(uint256)": "0b79cdda", + "isProveSuccess(uint256)": "25684280", + "layer2ChainId()": "03c7f4af", + "owner()": "8da5cb5b", + "proveState(uint64,bytes)": "59ef1120", + "proveStatus(uint256)": "e7047c04", + "renounceOwnership()": "715018a6", + "transferOwnership(address)": "f2fde38b", + "updateVerifier(address)": "97fc007c", + "verifier()": "2b7ac3f3" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ShadowRollup.BatchStore\",\"name\":\"_batchData\",\"type\":\"tuple\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatchStores\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawalRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blobVersionedHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isProveSuccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_batchIndex\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"proveState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"proveStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"params\":{\"_batchData\":\"The batch data\",\"_batchIndex\":\"The index of batch\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"ShadowRollup\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))\":{\"notice\":\"Commit a batch of transactions on layer 1.\"},\"layer2ChainId()\":{\"notice\":\"The chain id of the corresponding layer 2 chain.\"},\"updateVerifier(address)\":{\"notice\":\"Update the address verifier contract.\"},\"verifier()\":{\"notice\":\"The address of zkvm verifier.\"}},\"notice\":\"This contract maintains data for shadow rollup.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ShadowRollup.sol\":\"ShadowRollup\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/Context.sol\":{\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c\",\"dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h\"]},\"src/Ownable.sol\":{\"keccak256\":\"0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a\",\"dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB\"]},\"src/ShadowRollup.sol\":{\"keccak256\":\"0x904fc5504d39f106e724f054e70cf9dd6834045ed96d26d7721deda97dcf361c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0c12d8b897446a1fd27d4965ad9c0516e93e125c900fe1de87f6082b9ad51cca\",\"dweb:/ipfs/Qmce7X5ouUckXue4dV6uvr9KbewknMjiNfYGXNbTFy2hMX\"]},\"src/libs/EvmVerifier.sol\":{\"keccak256\":\"0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2\",\"dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR\"]},\"src/libs/ISP1Verifier.sol\":{\"keccak256\":\"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3\",\"dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q\"]},\"src/libs/PlonkVerifier.sol\":{\"keccak256\":\"0x806fd8b6b4ade67af043f4fa5f4115274d818322357d4204658baa0e89d8a22b\",\"license\":\"Apache-2.0\",\"urls\":[\"bzz-raw://ea68e04099672760854887295478f8849aa4bc9c45aac86735817b60ef93dff6\",\"dweb:/ipfs/QmbPVzAyYKiJPAjXQ1jAya7ozzhKYFmPL81akrjgyEirhf\"]},\"src/libs/SP1VerifierPlonk.sol\":{\"keccak256\":\"0x3b0264e71c5994b11eac26bd62d86f2d1d83b1ea80cf4ed1b63040af33d48c0b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://10d2be89afab2db15a1d3e2c3f197aa447e09ef012411f24cb12941bab9ac445\",\"dweb:/ipfs/QmfHGw55LFKqSH6unUTQgFzMwZ1T6ZeinpBxgnUJ4ayxoP\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.24+commit.e11b9ed9" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [ + { + "internalType": "uint64", + "name": "_chainId", + "type": "uint64" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousOwner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "OwnershipTransferred", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_batchIndex", + "type": "uint64" + }, + { + "internalType": "struct ShadowRollup.BatchStore", + "name": "_batchData", + "type": "tuple", + "components": [ + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "dataHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ] + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "commitBatch" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "committedBatchStores", + "outputs": [ + { + "internalType": "bytes32", + "name": "prevStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "postStateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "withdrawalRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "dataHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "blobVersionedHash", + "type": "bytes32" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_batchIndex", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "isProveSuccess", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "layer2ChainId", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_batchIndex", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "_proof", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "proveState" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "name": "proveStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ] + }, + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "name": "renounceOwnership" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transferOwnership" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_verifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "updateVerifier" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "verifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ] + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": { + "params": { + "_batchData": "The batch data", + "_batchIndex": "The index of batch" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "commitBatch(uint64,(bytes32,bytes32,bytes32,bytes32,bytes32))": { + "notice": "Commit a batch of transactions on layer 1." + }, + "layer2ChainId()": { + "notice": "The chain id of the corresponding layer 2 chain." + }, + "updateVerifier(address)": { + "notice": "Update the address verifier contract." + }, + "verifier()": { + "notice": "The address of zkvm verifier." + } + }, + "version": 1 + } + }, + "settings": { + "remappings": [ + "forge-std/=lib/forge-std/src/" + ], + "optimizer": { + "enabled": false, + "runs": 200 + }, + "metadata": { + "bytecodeHash": "ipfs" + }, + "compilationTarget": { + "src/ShadowRollup.sol": "ShadowRollup" + }, + "evmVersion": "cancun", + "libraries": {} + }, + "sources": { + "src/Context.sol": { + "keccak256": "0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439", + "urls": [ + "bzz-raw://a367861093b74443b137564d3f3c472f70bcf114739e62059c939f25e315706c", + "dweb:/ipfs/Qmd7JMpcxD9RuQjK3uM3EzJUgSqdN8vzp8eytEiuwxQJ6h" + ], + "license": "MIT" + }, + "src/Ownable.sol": { + "keccak256": "0x7c03cdb0bdf0104db4f87451fc7dd8fb4f94f06dbf176dfc06fd616c1b5937e8", + "urls": [ + "bzz-raw://cb707ccdda3e4c3a868bf01293d4c77729a2b0253d5bde0d9bcfea3b940adf7a", + "dweb:/ipfs/QmT7w8g3fZNY3uQKrPbm1uyLm1Md7kWsQB9QudgCWEBjaB" + ], + "license": "MIT" + }, + "src/ShadowRollup.sol": { + "keccak256": "0x904fc5504d39f106e724f054e70cf9dd6834045ed96d26d7721deda97dcf361c", + "urls": [ + "bzz-raw://0c12d8b897446a1fd27d4965ad9c0516e93e125c900fe1de87f6082b9ad51cca", + "dweb:/ipfs/Qmce7X5ouUckXue4dV6uvr9KbewknMjiNfYGXNbTFy2hMX" + ], + "license": "MIT" + }, + "src/libs/EvmVerifier.sol": { + "keccak256": "0x3dec49b04a203d4e6a883cbc4102f34258177cebea53f01db262d3311aa19ecb", + "urls": [ + "bzz-raw://9c5cec511c6683e92aef789739b66535f07b19e542eb976e6b4efb6ef6c22ee2", + "dweb:/ipfs/QmPwWSkBDNQrANnJp2zAMFbHg98MRAsvQZKwxBA7b5gGDR" + ], + "license": "MIT" + }, + "src/libs/ISP1Verifier.sol": { + "keccak256": "0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3", + "urls": [ + "bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3", + "dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q" + ], + "license": "MIT" + }, + "src/libs/PlonkVerifier.sol": { + "keccak256": "0x806fd8b6b4ade67af043f4fa5f4115274d818322357d4204658baa0e89d8a22b", + "urls": [ + "bzz-raw://ea68e04099672760854887295478f8849aa4bc9c45aac86735817b60ef93dff6", + "dweb:/ipfs/QmbPVzAyYKiJPAjXQ1jAya7ozzhKYFmPL81akrjgyEirhf" + ], + "license": "Apache-2.0" + }, + "src/libs/SP1VerifierPlonk.sol": { + "keccak256": "0x3b0264e71c5994b11eac26bd62d86f2d1d83b1ea80cf4ed1b63040af33d48c0b", + "urls": [ + "bzz-raw://10d2be89afab2db15a1d3e2c3f197aa447e09ef012411f24cb12941bab9ac445", + "dweb:/ipfs/QmfHGw55LFKqSH6unUTQgFzMwZ1T6ZeinpBxgnUJ4ayxoP" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "id": 21 } \ No newline at end of file diff --git a/prover/bin/shadow-prove/contracts/src/ShadowRollup.sol b/prover/bin/shadow-prove/contracts/src/ShadowRollup.sol index 1bde8dff5..62cd6c905 100644 --- a/prover/bin/shadow-prove/contracts/src/ShadowRollup.sol +++ b/prover/bin/shadow-prove/contracts/src/ShadowRollup.sol @@ -7,7 +7,6 @@ import {EvmVerifier} from "./libs/EvmVerifier.sol"; /// @title ShadowRollup /// @notice This contract maintains data for shadow rollup. contract ShadowRollup is Ownable { - /// @notice The chain id of the corresponding layer 2 chain. uint64 public immutable layer2ChainId; @@ -20,7 +19,6 @@ contract ShadowRollup is Ownable { bytes32 withdrawalRoot; bytes32 dataHash; bytes32 blobVersionedHash; - bytes32 sequencerSetVerifyHash; } mapping(uint256 => BatchStore) public committedBatchStores; @@ -41,10 +39,7 @@ contract ShadowRollup is Ownable { /// /// @param _batchIndex The index of batch /// @param _batchData The batch data - function commitBatch( - uint64 _batchIndex, - BatchStore calldata _batchData - ) external onlyOwner { + function commitBatch(uint64 _batchIndex, BatchStore calldata _batchData) external onlyOwner { committedBatchStores[_batchIndex] = _batchData; } @@ -59,17 +54,14 @@ contract ShadowRollup is Ownable { committedBatchStores[_batchIndex].prevStateRoot, committedBatchStores[_batchIndex].postStateRoot, committedBatchStores[_batchIndex].withdrawalRoot, - committedBatchStores[_batchIndex].sequencerSetVerifyHash, + bytes32(0), committedBatchStores[_batchIndex].dataHash, committedBatchStores[_batchIndex].blobVersionedHash ) ); // Verify zk-proof - EvmVerifier(verifier).verifyBatchProof( - _proof, - abi.encodePacked(_publicInputHash) - ); + EvmVerifier(verifier).verifyBatchProof(_proof, abi.encodePacked(_publicInputHash)); proveStatus[_batchIndex] = true; } diff --git a/prover/bin/shadow-prove/src/execute.rs b/prover/bin/shadow-prove/src/execute.rs index 1a5142e6e..4792c1fe0 100644 --- a/prover/bin/shadow-prove/src/execute.rs +++ b/prover/bin/shadow-prove/src/execute.rs @@ -252,7 +252,6 @@ mod tests { &inputs, B256::default(), B256::default(), - B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); @@ -268,7 +267,6 @@ mod tests { &inputs, B256::default(), B256::default(), - B256::default(), ); println!("batch_info: {batch_info:?}"); println!("batch_info.data_hash: {:?}", hex::encode_prefixed(batch_info.data_hash())); diff --git a/prover/bin/shadow-prove/src/shadow_rollup.rs b/prover/bin/shadow-prove/src/shadow_rollup.rs index df1f7292c..4e47dfa12 100644 --- a/prover/bin/shadow-prove/src/shadow_rollup.rs +++ b/prover/bin/shadow-prove/src/shadow_rollup.rs @@ -331,7 +331,7 @@ where // * prevStateHash 32 bytes32 89 Preview state root // * postStateHash 32 bytes32 121 Post state root // * withdrawRootHash 32 bytes32 153 L2 withdrawal tree root hash - // * sequencerSetVerifyHash 32 bytes32 185 L2 sequencers set verify hash + // * sequencerSetVerifyHash 32 0bytes32 185 L2 sequencers set verify hash // * parentBatchHash 32 bytes32 217 The parent batch hash // * skippedL1MessageBitmap dynamic uint256[] 249 A bitmap to indicate which L1 messages are skipped in the batch // @dev Below is the feilds for `BatchHeader` V1 @@ -359,11 +359,6 @@ where .unwrap_or_default() .try_into() .unwrap_or_default(), - sequencerSetVerifyHash: batch_header - .get(185..217) - .unwrap_or_default() - .try_into() - .unwrap_or_default(), }; // Commit the shadow batch. @@ -459,28 +454,26 @@ where let post_state_root: &[u8] = batch_header.get(121..153).unwrap_or_default(); let withdrawal_root: &[u8] = batch_header.get(153..185).unwrap_or_default(); let data_hash: &[u8] = batch_header.get(25..57).unwrap_or_default(); - let sequencer_set_verify_hash: &[u8] = batch_header.get(185..217).unwrap_or_default(); // All versions: blob input at offset 57 (aggregated hash for V2, versioned hash for V0/V1) let blob_input: &[u8] = batch_header.get(57..89).unwrap_or_default(); log::info!( "calc_batch_pi, version = {}, prevStateRoot = {:?}, postStateRoot = {:?}, withdrawalRoot = {:?}, - dataHash = {:?}, blobInput = {:?}, sequencerSetVerifyHash = {:?}", + dataHash = {:?}, blobInput = {:?}", version, hex::encode_prefixed(prev_state_root), hex::encode_prefixed(post_state_root), hex::encode_prefixed(withdrawal_root), hex::encode_prefixed(data_hash), hex::encode_prefixed(blob_input), - hex::encode_prefixed(sequencer_set_verify_hash), ); let mut hasher = Keccak256::new(); hasher.update(chain_id.to_be_bytes()); hasher.update(prev_state_root); hasher.update(post_state_root); hasher.update(withdrawal_root); - hasher.update(sequencer_set_verify_hash); + hasher.update(&B256::default()); hasher.update(data_hash); hasher.update(blob_input); Ok(hasher.finalize()) @@ -598,29 +591,22 @@ async fn test_inspect_batch_header() { .unwrap_or_default() .try_into() .unwrap_or_default(), - sequencerSetVerifyHash: batch_header - .get(185..217) - .unwrap_or_default() - .try_into() - .unwrap_or_default(), }; println!( "sync batch of {:?}, prevStateRoot = {:?}, postStateRoot = {:?}, withdrawalRoot = {:?}, - dataHash = {:?}, blobVersionedHash = {:?}, sequencerSetVerifyHash = {:?}", + dataHash = {:?}, blobVersionedHash = {:?}", "batch_info.batch_index", hex::encode(batch_store.prevStateRoot.as_slice()), hex::encode(batch_store.postStateRoot.as_slice()), hex::encode(batch_store.withdrawalRoot.as_slice()), hex::encode(batch_store.dataHash.as_slice()), hex::encode(batch_store.blobVersionedHash.as_slice()), - hex::encode(batch_store.sequencerSetVerifyHash.as_slice()), ); // prevStateRoot = // "13a862a764f09e1300ad485fadcc130741d400e8d5be3dbb968901e6590e25ca", postStateRoot = // "20a6aa14638839f76d2b233499439e45cd315434f9628902793c421ec71fcb0c", withdrawalRoot = // "eda0cccc67b86712eea4536d186be3d412b86c4c56741d641d1bbfdd26b5d40b", dataHash = // "89a1c4692d97c7a4a516b35bc46963da3425af5273cb5a7b8ee2cdcf41c6fa65", blobVersionedHash = - // "013f8fabf23fba03c52572d3403d175d952937cdd78bb8e9e06eb6ffa751fd2a", sequencerSetVerifyHash = - // "60f10881edf25485d6d9db1c3a634c002bf4da64cce0f9a0f528e00f1ead3dec" + // "013f8fabf23fba03c52572d3403d175d952937cdd78bb8e9e06eb6ffa751fd2a" } diff --git a/prover/crates/executor/client/src/lib.rs b/prover/crates/executor/client/src/lib.rs index 7524e1e6f..cdf6c38d0 100644 --- a/prover/crates/executor/client/src/lib.rs +++ b/prover/crates/executor/client/src/lib.rs @@ -25,13 +25,12 @@ pub fn verify(input: ExecutorInput) -> Result { #[cfg(not(target_os = "zkvm"))] log::info!( "cacl pi hash, prevStateRoot = {:?}, postStateRoot = {:?}, withdrawalRoot = {:?}, - dataHash = {:?}, blobVersionedHashes = {:?}, sequencerSetVerifyHash = {:?}, batch_version = {}", + dataHash = {:?}, blobVersionedHashes = {:?}, batch_version = {}", hex::encode(batch_info.prev_state_root().as_slice()), hex::encode(batch_info.post_state_root().as_slice()), hex::encode(batch_info.withdraw_root().as_slice()), hex::encode(batch_info.data_hash().as_slice()), versioned_hashes.iter().map(|h| hex::encode(h.as_slice())).collect::>(), - hex::encode(batch_info.sequencer_root().as_slice()), input.batch_version, ); let public_input_hash = match input.batch_version { diff --git a/prover/crates/executor/client/src/types/batch.rs b/prover/crates/executor/client/src/types/batch.rs index 5cb7b7c9a..e7defb535 100644 --- a/prover/crates/executor/client/src/types/batch.rs +++ b/prover/crates/executor/client/src/types/batch.rs @@ -16,8 +16,7 @@ pub struct BatchInfo { pub post_state_root: B256, /// withdraw_root pub withdraw_root: Option, - /// sequencer_root - pub sequencer_root: Option, + /// l1msg data hash data_hash: B256, } @@ -27,7 +26,6 @@ impl BatchInfo { block_inputs: &[BlockInput], post_state_root: B256, withdraw_root: B256, - sequencer_root: B256, ) -> Self { let blocks = block_inputs.iter().map(|x| x.current_block.clone()).collect::>(); let chain_id = blocks.first().unwrap().chain_id; @@ -48,7 +46,6 @@ impl BatchInfo { prev_state_root, post_state_root, withdraw_root: Some(withdraw_root), - sequencer_root: Some(sequencer_root), data_hash: l1_data_hash, } } @@ -70,7 +67,7 @@ impl BatchInfo { hasher.update(self.prev_state_root.as_slice()); hasher.update(self.post_state_root.as_slice()); hasher.update(self.withdraw_root.unwrap().as_slice()); - hasher.update(self.sequencer_root.unwrap().as_slice()); + hasher.update(B256::ZERO.as_slice()); hasher.update(self.data_hash.as_slice()); hasher.update(versioned_hash.as_slice()); @@ -90,7 +87,7 @@ impl BatchInfo { hasher.update(self.prev_state_root.as_slice()); hasher.update(self.post_state_root.as_slice()); hasher.update(self.withdraw_root.unwrap().as_slice()); - hasher.update(self.sequencer_root.unwrap().as_slice()); + hasher.update(B256::ZERO.as_slice()); hasher.update(self.data_hash.as_slice()); hasher.update(blob_hashes_hash.as_slice()); hasher.finalize() @@ -108,7 +105,6 @@ impl BatchInfo { prev_state_root: B256::ZERO, post_state_root: B256::ZERO, withdraw_root: Some(B256::ZERO), - sequencer_root: Some(B256::ZERO), data_hash: B256::ZERO, } } @@ -128,11 +124,6 @@ impl BatchInfo { self.withdraw_root.expect("get withdraw_root") } - /// Sequencer root after this chunk - pub fn sequencer_root(&self) -> B256 { - self.sequencer_root.expect("get sequencer_root") - } - /// Data hash of this chunk pub fn data_hash(&self) -> B256 { self.data_hash diff --git a/prover/crates/executor/client/src/verifier/evm_verifier.rs b/prover/crates/executor/client/src/verifier/evm_verifier.rs index e35083bc7..05a200098 100644 --- a/prover/crates/executor/client/src/verifier/evm_verifier.rs +++ b/prover/crates/executor/client/src/verifier/evm_verifier.rs @@ -2,9 +2,7 @@ use crate::types::batch::BatchInfo; use crate::types::error::ClientError; use crate::types::input::BlockInput; use prover_executor_core::MorphExecutor; -use prover_primitives::predeployed::l2_to_l1_message::{ - SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, -}; +use prover_primitives::predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}; use reth_trie::{HashedPostState, KeccakKeyHasher}; use revm::context::BlockEnv; use revm::database::State; @@ -50,14 +48,11 @@ fn execute(mut block_inputs: Vec) -> Result // Tt is derived from the state of the last verified block. let post_withdraw_root = latest_block.get_storage_value(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT)?; - let post_sequencer_root = - latest_block.get_storage_value(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT)?; Ok(BatchInfo::from_block_inputs( &block_inputs, latest_block.current_block.post_state_root, post_withdraw_root.into(), - post_sequencer_root.into(), )) } diff --git a/prover/crates/executor/host/src/execute.rs b/prover/crates/executor/host/src/execute.rs index 10dd2ac31..b4cb4ba68 100644 --- a/prover/crates/executor/host/src/execute.rs +++ b/prover/crates/executor/host/src/execute.rs @@ -3,9 +3,7 @@ use alloy_provider::{DynProvider, Provider}; use anyhow::{bail, Context}; use prover_executor_core::MorphExecutor; use prover_primitives::{ - predeployed::l2_to_l1_message::{ - SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT, WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT, - }, + predeployed::l2_to_l1_message::{WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT}, TxTrace, }; use prover_storage_rpc::basic_rpc_db::{BasicRpcDb, RpcDb}; @@ -136,14 +134,6 @@ async fn load_predeployed_contracts( .fetch_storage_at(WITHDRAW_ROOT_ADDRESS, WITHDRAW_ROOT_SLOT) .await .context("failed to fetch WITHDRAW_ROOT_ADDRESS storage slot")?; - rpc_db - .fetch_account_info(SEQUENCER_ROOT_ADDRESS) - .await - .context("failed to fetch SEQUENCER_ROOT_ADDRESS account info")?; - rpc_db - .fetch_storage_at(SEQUENCER_ROOT_ADDRESS, SEQUENCER_ROOT_SLOT) - .await - .context("failed to fetch SEQUENCER_ROOT_ADDRESS storage slot")?; Ok(()) } diff --git a/prover/crates/primitives/src/predeployed.rs b/prover/crates/primitives/src/predeployed.rs index fe42ed8c6..dd5800071 100644 --- a/prover/crates/primitives/src/predeployed.rs +++ b/prover/crates/primitives/src/predeployed.rs @@ -37,10 +37,4 @@ pub mod l2_to_l1_message { address!("0x5300000000000000000000000000000000000001"); /// Withdraw root slot pub const WITHDRAW_ROOT_SLOT: U256 = uint!(33_U256); - - /// Sequencer root address - pub const SEQUENCER_ROOT_ADDRESS: Address = - address!("0x5300000000000000000000000000000000000017"); - /// Sequencer root slot - pub const SEQUENCER_ROOT_SLOT: U256 = uint!(101_U256); } From 56b63f8b50eb035e2bdea5aaa75d089d289c0bee Mon Sep 17 00:00:00 2001 From: Kathy <22675649+anylots@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:23:39 +0800 Subject: [PATCH 35/38] gen prover elf-vkey & fix clippy --- contracts/src/deploy-config/holesky.ts | 2 +- contracts/src/deploy-config/hoodi.ts | 2 +- contracts/src/deploy-config/l1.ts | 2 +- contracts/src/deploy-config/qanetl1.ts | 2 +- contracts/src/deploy-config/sepolia.ts | 2 +- contracts/src/deploy-config/testnetl1.ts | 2 +- prover/bin/client/elf/verifier-client | Bin 6896208 -> 6896280 bytes prover/bin/shadow-prove/contracts/README.md | 2 +- prover/bin/shadow-prove/src/shadow_rollup.rs | 2 +- prover/contracts/README.md | 2 +- prover/crates/mpt/src/mpt.rs | 4 ++-- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/src/deploy-config/holesky.ts b/contracts/src/deploy-config/holesky.ts index c451f8240..adf4b11b2 100644 --- a/contracts/src/deploy-config/holesky.ts +++ b/contracts/src/deploy-config/holesky.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/hoodi.ts b/contracts/src/deploy-config/hoodi.ts index ab7a0bf6e..aef1e7295 100644 --- a/contracts/src/deploy-config/hoodi.ts +++ b/contracts/src/deploy-config/hoodi.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/l1.ts b/contracts/src/deploy-config/l1.ts index a3a50c0ff..979010c87 100644 --- a/contracts/src/deploy-config/l1.ts +++ b/contracts/src/deploy-config/l1.ts @@ -17,7 +17,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', // rollup contract config // initialize config finalizationPeriodSeconds: 10, diff --git a/contracts/src/deploy-config/qanetl1.ts b/contracts/src/deploy-config/qanetl1.ts index 4f504a49b..278c2aa3b 100644 --- a/contracts/src/deploy-config/qanetl1.ts +++ b/contracts/src/deploy-config/qanetl1.ts @@ -14,7 +14,7 @@ const config = { l2BaseFee: 0.1, // Gwei // verify contract config - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', // rollup contract config // initialize config finalizationPeriodSeconds: 600, diff --git a/contracts/src/deploy-config/sepolia.ts b/contracts/src/deploy-config/sepolia.ts index 94d94cd78..14117dac6 100644 --- a/contracts/src/deploy-config/sepolia.ts +++ b/contracts/src/deploy-config/sepolia.ts @@ -18,7 +18,7 @@ const config = { /** * ---to---legacy property */ - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', rollupMinDeposit: 0.0001, rollupProofWindow: 86400, rollupGenesisBlockNumber: 0, diff --git a/contracts/src/deploy-config/testnetl1.ts b/contracts/src/deploy-config/testnetl1.ts index adf9520db..0d0659ef8 100644 --- a/contracts/src/deploy-config/testnetl1.ts +++ b/contracts/src/deploy-config/testnetl1.ts @@ -13,7 +13,7 @@ const config = { sequencerWindowSize: 200, channelTimeout: 120, - programVkey: '0x00c684101523a06415be6d72d011eebaf465b4c1da4e3b18ab052a29d7ac6e88', + programVkey: '0x00da5ade7ec0ec902618c53b616ac96f47de1cb79b450f815a7c6cbebd6ffaef', rollupMinDeposit: 1, rollupProofWindow: 100, rollupGenesisBlockNumber: 0, diff --git a/prover/bin/client/elf/verifier-client b/prover/bin/client/elf/verifier-client index 0e0a8f4347b7e77de069dea1d32a3154e20b90f4..04703b9581dbdacbc8e27099b76360291f53ca1c 100755 GIT binary patch delta 1303110 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 mUm*3M^b^R5@pr;(jrgpErfLWk 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%0DT;uJk3$IwI>k$zaf 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�isz7gt;qM~Q_XsqM!+0Ig=c_oo-O9D4 z`5rzQOpEsLh8LO`@|`fra9E@QjRUV#{50@7#m@n+S9}Jz?+tK=?phe46u%WbP4R`` z>54xHo}u{T#7&3);tu=X2n^i^Fbs|0k&rL)+y!2b5t6SmJ8T{wK=P0v8F9*po1zvD z>;<8(gg(X^X#V@)3@8S1=tta~aBATo50tNlUbyIIK_9mdkElFoZiZgC=sz}k^L4iU zquHShmJ^D&2g1c64ZIS1;irOcReXx&RPAa%xCr`A(xd)4R5lDL1Kpaq47^tHtH4wD zbM@DPXDMC)o;avW&-oX?klbysEh?1+ia%_5&z>!ZK3C~ig4Zd&rU-KrwSQNOY~p%y zFms=F5c2>Jkaxg*o|=Htj|8t*{Alpl!EXFh!IOMtm;yt#;+f#(ieG9uot|-jk9K-_ z&{r${Z16hpuKD+2*r6PX!Q*1x9^4C_uXrVRiQ-R#SGnBxo`a#yHF)d6GY)VQzZr%% z6E_=68ukg!J%-7+v7*UBM)?W4S2TV>yRKH9gr^u{2uz;5WSuM4mf1MK^hc)8xLJ^h=VDx zBZ-?4x*mEw9`vR|zewrxz+>Xv4%~bj&i^UOP+}c=R`o&zDpmT$;FXG3fY&MhBzS$C z@3yE825+d#-vp0Rycs-A@h#x#if;$c5H9QQUl{VlV8)sL^)Kcr(0m`_W(q#S6vVUK zJ0AKH73W0oYQ_DDFliQA8Gt%U>Cll}KG9J)9>J|%7%v~~n1kYoGBcX0yYk|3M7(Kkb10K>=76L&wt z^(h?E<2iviOu3sA2$uwz#BGD1mnmq3el57@H$k6q2*BW~&jdFQG`h#1te3+e zPcFpaN^p6oBs>pXo@NQZ7M$+y?M%isqn>gpc0S3997KcJ`xjPnq3wX>3&q**3 zT#jy{pAT-2TmtED@nU=a?>;n&?M^tziAea};BvGQeh;{uh=iAd7veH4{66p^Ul|^N zp;GY&!Rr;T0GD%sBzOcIx7mWdN5SPTyKDX*vj#cqcImw;%X_}wzv4%JKZd;6ybUe~ z{lr{eY>o%N`FG~>K%4Kimm?{`rM_soB=-+=>rYls_t9(Wo~*8@te-tRJq z!$3B8)nl-s!Vm+VeYnd5;E6}LJP|xu@f7e>%e&^2J{@We5#FJApdt;L6ozLIH%H1< z(95qz-wgfbD$Z?|(~rT1Hpt|^1BTjA1M&O7y(G71mEipqe+oQqtgC++e39ZCiBo=h zVso_X&x%vg*MT-9iyf{srXDVPQQ4UXlN1yB_ zcmX^{@&AIyD&7Ph*TpgapTm%Uikskj@Z@xt{{fz&c;vl25~+$01W!}^ARmU>Gu;G- zf!8UX0=`!9)4=N$pGw?JS?Q%5Uw%t!4fOuD3*E%8!LUQ|M&hR0TTs;jERUVgcPf3~ z`&i!ry_|gyCvIvk^&*?Md;J{`!+16zyyvBZPgML|B#7?A&p#zW5%i0c{vPl$hg1Hg zFjP1O+8~i2K_z$}`c|d?5`3%T+rYOe{-=p=&NEpmL3|kxQQ|arYQ};mD}Ew)s^Vu6 zH&d3c;?IG8F6q0+p9cIk7>ZS(Qt(BJFGGSfm7oFol}i61cy%}D{99nC?Kar?{~5eV z@lNm-#rL?MN3Kor{lPmGA8|jPXGUU2ld4OCLx06j0GAz5^l9J)SZ2Z}h2a^*&D50m z7`hmE+yVz#uM%h;__iFkCgy{8D!v#ADiB|O8RaGDV=m)3UGx7Y9Gc*;Co=y6hd4M$ zgZ_oS2KoRDqaNTXNLTt}z)M{2d#94Y429R1*Riy8792`l2k#c>+f?FJ#LZ6E3VkaY zvBO9%P{O+)EgmVpo^@|C?g5vR5(daCEw|4zBfRP}T!;JMAQu~PcmP~3D#9NGmurFW z3UJxNg+BtG*2m|f6T_o0$d)YpF>u*Rg;#->pcsX(2AAb0{AqAmHMpPiyk}u(Qh{p0 zrP?LXi{P?qgue_f#VGt$@FYx`aK9b~DHbvO7hH-?_?zJQD$rZtQWK(Y1ee+pzRB|4 zzY4sn*u)9h5Uzot_;xozK6uuhF29wyITaM5 z#{)6Ek3*lW^tI5}LvN?g?zBy5s?OL z=RHG~pS&Ox`73j-YR{9?eZSwBOHpsY9&_vt<`>W$*v%&khLigYw4be%Wmy3J6*aWC z^G4({Q*=FhwtH~OD%$Gy3_eSL{4rKVKiRD&BniB8p*!J6ffwH6@?*f0|Ksvgz{e|o z8gt)UqzqHwuwC&?@YGT_K{j}$;xoak6~7!jd5MV=vddfvL$NhTeR$pt;O&afw>-j& z$#g5T7`z3GS|Z&EzCDziE6Cl}&~u{hu@mJV@dpYE9qEsN>;GgfBU=qVyOX)hP$ORJ zJ?UTOGNW_B7wlp#166`Jm(#_LKFfQd$0Ox=MR0g#PcB56p&B@x*q^V0(s8?ulC20_ zIxhV6;FJ|qh^1VJ&)HF+N4odA^ZNpLQ_$tF6StfEZhVD50Ik>teT&j}Kwl2MwBq20 z?cVHroyy^GHh7WcZsOyJo5b5ypv$0-Rr=Y`*FZlK4SfjufYpZ-;^S~=Q3*D~Az3B( z9QqXK<1Uje+Ypl zU?k+XxZZ?*u8Q+c82&Nhd_WDd<1f$qB3AH_ma0Izh2i@VHzRZa8YHXcMCezlIH&gH zJpUO8G*$(=1rBv8P!V{8;`bmm4u>7e;rB4S&q|In z9dYCibqsN{!|K(PWI25YoBxEnoQ{GaPVqDZ%0>~%@;DRvWTihl44(#`0e#o{o1qMn zU>10uN^m`Rf#OBra}~b_ywc^qcW>_o?-AmrxSqw3N|C+|{aQDWwdNIpq29{L?B&V(@hJj7XL;+XN5t#LjaqMvkY;*K!< zKJY}PFAu{X15Xdp+xdSIhRhIyng17wn;u8)!CP;@K>D`@`W&VI8Tth1Uaol1@}8x-)N)&@A>&WYU5dwW(&IFAVPppvsWdbid@71d zMnaytjHf#{^Cm`Vs1)xV;L^}odqt&SC-22YBy*pOqANrZ$&dz+_+@YzQsJG%%~z|* zR8B;kihvm%mTkTpQakHS*ef zC-i=%a)_#8hZ;D@&>czKyr7Y*^d~~!p!B&`Pj5lF)~%td!4bcE{%64;fn+RZgG&#D z7g*l2xNfw(=RSDl?wDeXXsUf{DdoSJ9D19A`@L$Y7~FVa$2rxnSB6#gVMKz;olH9HIcq2?&#!58T|y$ajOb6C=5TCxCwLz1v1kj z_q>y!->%|J?a6umFM%O)om;&*Vfbv~CULe(TmgNoinBZnfBFgB(Os_seFBF>73hmF z{0HKuL2n_B+-&dvB#&sCigTcFUl|g}U;>?kKyn{*4jeL-J}V5r3~?Sr99hPt(B~pf z*ZR9(8DyC~ia^h*K<`37S2gH;@I{J$i8z71xK^-meQ(dzJVa&6VK8ws5*{1^XwfOq z*D3uOVR$Cue1Q(g&9-m#e$VB!z#4dY$S9bnh^+)%ic$DNaH%cfi^1)x=^B5s zE`dSjOdQIAK&eZumdTd%(# zZ@sbu1`w!vHQmwmw)Jidli=+z3Em~%Tb%YVaenBE6FUCXs-MCH+NatSY0n<-YkAKe z4%Bt0;Prtbg>SEAvf3l>T?( zwEsnTQa}OqeftM-1`?IWHsd$X# zbZZvpo`wheFv#4aR=gqLGWWuVg3H_s4}ixfh-YE^{yZ z2ymHu;YWhY+zUS%oaWw~8N1hC3Jfy$;&42;%)Rgv!Da4+pA0T@FMK?>%sq3;e+CSB z>eGv7f=f+Eph@7ezJ+Ii%la06j^(l@gnHh2hWlR6jpYI|^tQ1Sg$Z<<XbuaOhADe}H!?-q|yd zjkC-0oH($Z5w%`$i(}8u6T|&1mU)s^j}wj$2Yhe%N+15#TS5Yd&|`?CQe(p@1@7_n9A|C z4h}n%!v=Qna-o+SgP)*}dfQF#7kISdyVY{Xk}VG@qdlyFCK(B&$Nj;Vs5gP`11=2` z{l4HuD$XFw)f}7rvDVOY8Qi-+9tI&$02w|2FCD;pvV9&vwgV|nZ_96dZ;45N264*Y zGx3>W0$m>_&>YKq#oJYIkgp5D6=&>+?s=@@?Z1wcT&}yhZ4Z}YtZeHKmx{Yfk zo4z;8{+so@DGGYpqypUt9vIrS@U6bca{BRcRb01$m%QT^V<~u<;>&y(DwW|$@M^_h z1aI5qCfESJP4Ug(9g2Se?t4vcpdVmpZ*_SG_;$tny}%=vtwv}7c%|Zl!P}U3&ws!g z`g-x7yNO4Dw zd0x5U<}q50GCXD-BD}ysZqYpro~`(c;FXHkgSRREmc$>1$7s@`42^2q95-5I&<=q>O?G^pkrQpf_k8aWB!?5iqm(K&=q4*;3gr8mgQt%|j zt1PFD4h`*Ee`{a}jBtCr7Cc+=H^D0vZ;}Lxe=70go%p`DRT8)c?|AZ zjOqug@?%~yv!D(+Lla}dF#Jl(>9c2QAIbwS-R|yNh0J|#r7{%5p<3}J#Lbaz z%6OkBsy}O8;XHzX0Az9bY zL7%Mj_0V@fZ`ZrY|2-VimBUW(48{Ab*P9x#IU-~p_=((w+Ti&zM&m!L2rZU^=>6dfl>TH>gwTM-n&s$x1&J`qBYz{OQp9nQ)K?mUqD+b3fPNemG=9FITI2 z=xdd}5&9&h-wAyi>$}%q-+JyD3^LN*Zp2N`3K2+NxEu?8r%HTc7=AM1+=Dp$WlJQGmMX@GX4QL zoIIRg7L{#I-sv{+VCJ&TCF1p$L5Unk=1bz7Pu#reND4?^P5F`eDV|i27_J?I1gI3@ ze}GE`2`>w-|BAjd;bn|QyBgJ3!;D6KaQzqLHUr%kH`&`(fJ>Rpz_9$+X7j(ZQR(4w zcR5?ZHt=b~+zsVt@NEH?{|eqQ+~vPp-g6E+EdM3A@r%g=XFPcbkCZfGC8nZdG;>MT zA6K;7j$$s2D+T}QXy($0X~_FG_jUN|yq9DqxNVHLyk{FnTHak}7&)&hp3_L29eAcW zn)JP0$uo%4mgIX$349@x*S&6LgXe+EoUH_pRs22T=9rj1*6qM%@VcX2{yBKPodeC#IBQ5Va)VmY!ZAiyhJ^hT4 z>Oc~BUWz*sM-iv|Jrf^e9eO4{mUwT8FF}G0$GHhE1@AcC<+H$JQpdT+#G7G=OLZOY z08du@UhoXX9|q4-{7LY(72o2SQO5Qm}0KzuG7gpVR_0=0q5)Z7fcaM9li{Wj?3{qpZYZ@4r6 zo8b_b#w`_xgWu!^36}(ifKP;8cmjBy;)j9PpWL-NIR7{pTDlE3)~UqJxwR5iEe*N` z`ZlG%3B3O)T?uTQ+reWLU-G6sCenAlD#J1)K5!IYobZyWw-JGAmHq?hx1*tlVJQBA zey!5)v5`C0=;@c4?0db^b2R3lWVor6YW>4=R7-ECZ{*OKslCJ#DgE`6d^DY2S zR{V0}retzeoF&jtRQfXT4CY0beFRlEUl5-5%xe+l#(9Cj#&o!}jc|DUcifX{Mj|M*=^hL!P-hVUSahD9`*48sr& zVF;rziY9rDrhAAc!?0{JtXCK%!_p{>ipem9VVH#Z3&Su(|LdId`|Wwo^|bvzAHDzY z^}DX?oa>zXoO9pLy=Mbfy9(v12JJ80TvW+9-rNgDfTu*c8~-r~RHy=73WxNlg9Mf* z4d5AyUyC?pD$WAvbCv$F)mV?lDnkPT)u}*V*g)~WMza=t&J6!p@ijP?5!-tCPbYX= zxQ*}dJq%od>F^_XE7l|OpTW5hl6Ql1K_&kKoXbw{_4gMHX_%#S_y;^!@!(A}#?kAZ z`T^i&NmRhJpRZxtm^5XWr02R2zT7kztA*WxH(U8GmoGnpMY~SFT!4!pY8PA7`XFnf28AF z=*jCHmm5A@wKR-93W*i(f3)LVXsKTS&V`eFY>v}&9VG7ocgvbgFdCjX#yN1EB0v9F z$GPl~{{_xvgnaUGPR~_=yd9iZx#eb-?p?LbFESD**@2S7hq~DFgquCR{1~@f@qqaO z^yHjrZQ$L|lYa`n@>qY_`_}O=Xjg_`#b9=r(&27F=M&kTTip5?9OnnxN4U|?g`O|v zo(6rg(w_mo&hp+%T|P{QVS{qG0z8uIC!PVGp?Fyz{5IjHp|xnJJx7}SORR(Jsp=YP z1mFH(e>q$Ro`^s!^-JIp#a{t0RD7lIW6W~JQZvx&a9~NvSA(+$~E_5c%NmONXO3XE9UhPg{urL7ti#8^9MSp7@rV+iiLN6iWfG zJ86GP1sodk!DSO?Lc1>ULnMc~2tF$qL}C3vFZ*9*6=(zmL_ zkHKN6a%ce0QoIQ~NAVW$35vIYPdZ;c#rYbBGUd<--lX_%md8H>=>ccQF!aIS;H-2I z;4g*zTXp4caxwIK+YD*^#jx1{Ztihvx~;Hek*agG4*ywK+-g0Htc=3+P#hA!nW z5xiURso<3p{RGp%*InfEnT!+5P5wDBBwXw}+zy^z=<|8t`HDYgdHi?iJpmr1yPb-I z@T73bFK&%ee`@D_N1;-6UFF9?eg{H@?KIMgbK4)6_%{{Ws+>?i&UJV)`( z-*ZEp=Xmt`OM#)`IzP~E;2nzZ58kc#Xz-F5ew<-Qwb`;OBA1vIQ2-pBP!7XeOFZP@_!6N@=U)6-++$| zef}$Wsp7#JSD}@P4+5{g(T}qu{}B30W!PIBOz8?x39fXfB2b6YpAUVps@xpt({J(< zSAmy=Wxinn3@a6X8oW#KmxP;!rXexELHs-Dhu-SP{~bIVym$NueBc6Qs~+qx+$_nt zD$r=?JNEPE%Ei#9-R>v83OuOvco>v2fo}+I2cNF^JmIFti6dNMevQm3=xde!J@A!^ ze_`Xu4NC-pBABIHe&~AKq8x^RPp|QM5DWufuJ{P>PQ}LvHyx-ml{59{>s^<^A>{!- z!GFOs6~76An$!?1hCW;Amw_*MFdE;Ee=`iNF$PnN50N0)-<5h#RH)xaScqz)fsAQu z@Z|YE-x)kh@!=og+wAg`;ZQhCQT#aYCdE$&U$6K?;ilBrV2JtE%XdJZ_&>E!)X?y- z--9Q>>lJSVk1X)@uYnI!d<}RSIj_I9Fr?FfQg;bAXT6?!mtX^a0shZ6Hw5GB{KNx4 zc6_?x{{hc=+}DS@!BD3R2Y|0sJc|jQ@B7M{kU+6bzDdO~C^77Art%W|{>REqD@)HcjD$oW5N>&a2T%~ zz5$=0_^;qaiue1}^|%u~9&LIoKk35Fo>KgzdSG)H9MTSS3l1A}5ge*jf@$EjiihA0 zikE{g@8uZ(`(SA8HQ0s*kAk-;{w(-<#a{vMR{S0C#Kr!QwX>zel;JyZFq5TK4NXeB zD_xe-?@XaU<p+Ln?TpgU*M3!c%GyxDbXO6{rZj z5L=tJkl$iakG7ufgEt@$_hvR|DfpzP{h?U}UZ?o` zAq@4(@FjS6gCA%ec#q=0^ud1vPg&x}=>ZRiD#PC}bSS<>ha2PIIX}=4;bx4pv2OG8 zx}%^^SNc5YPj~vT_Y0k8ScmwhrZd6$@q5NT^^ozO z0|T#nI^7P=>zlj+oL3F`J>Z$Rn#k`3&sY3D!_7kgF0pi|fdiLP@`u3f-2>8KVjhUg$^6QyRdnXZv^K<0P_A{x}oGfJ^5zfJbRNTS}yw^?+|I& z3J$yrAs-ChiX$!gHsCz!lBa<4L`yyd+^(3s#WBVmVZhQzeXz6T@t;masz#)Y8xjuN z!F}w*g)jogi-enxiTLC^4?1pQCPyM>VNm1gYd;&A<9oGZb(evv;bT;lH=@BwxK z670B>OU&oU%kAw>5Y$w?GFaOCnV8MD6Z2wBLwk1}>Nqc6L<=quZu%jo1-qcvz|aCc z7YF|G#^9Y@94-#zdBP=*yzPyxErLL=z@ZvnmCbi&2JC`{V!(NxI!3r@5cg&?@61m* zIQM48Sp)9&V0ku-UrPxhySfD2k|w!0!5&q+Z6}2~-j2KcF?Y3vjs?$Gd>nY0;^%;; zFZH+XOTecqewE{4P_GOj98w$oK(~PxDP9F$qWHt$)rvm_-femB(i8;Gz)<{xpZF#4 zoMk>=4PL7FN5aivr4@&jeNpg!Yt0zSuX)GnP5!|!w8R>O?E5jskP9i3_1e|k%{4#KkJ^AI}9Afe!@Q|gW;VNs0-v|C{dHko; zC*`_zit7j0qc(7^A2rwkPC4E!N2pvF@Ncu<4FgLTL5to8XX(gOPH=%(Ir7tmn}w5; zbR-tw_2BNh4}voLq*KPf5Wn!lS-Jr&y;gd>sn6Nx3pbBU7hz7Y$J?%Rla3ti54IC- zCTRsGX)zjfgmC#%FZul%1nR^laz6r*Gth(J^{f3^Js*6H;)_iJiJ$hS(+@N4lb_?h zb`3Q=X8j9-6JQwoj-TKp@FK;}7H$%(1Rv?*2P>c_2M%6?z6W}FWa{#d_{Oz}20Dxs zZW1K5x(4wD(Rt95Q~v<;)1mKzVZgU8J~{ORzm=o8NigYMmwxo4%Z1c36ei``dKji4Lv#a|3Y60Jv$bD z=i-z1j{l8fFbUGy{RR#AKj%Qs1OtT|eLM6EV3-X(IrVd(Fa6BxfZUpY?-I~Jhrz;4 zf`reVgIq!Orvmz34u^ZF|HA2cklJazi=P0__`3-2Z~ofUP#C7eG7k>qba=oz$lsk% z`W=373CO7*D%^IU!!?LQa3AyuhWFNAylUW34F}GN9e#8P$a@nAHwngm=@QI>;Xdfe zsjq>)6?)Skn}3I&Tml;CFjTlnFlntzzy{q1JvsF?(5HUo^vM{q9lBh6a_Wb6$>(z> zLE1Xi12~Y=p+>mTFM^(PV#l9df?f`Xoh^?py^IsF+-!2O^_Ty54{M0u<@OT3slDK2 ztCt3S?K;2&XZOL+1#hOF`3vaqtsiJ2cul9zF9weUncf4aOD&g!iTZOhQ!J0)*2AgR z5Z~iz!Z+39c~&ngU6P;p(LVU&;Omrrk>g>|JlGHP6dW42_W3j5;Y}&hQie(g*(ye7Vy1fLD)>iDUBr4a0_`V+_Lo1y2~~ z^M1d$+1`Gt&lAAA&i47{;BDvld`sbyKfZK>tV4Y1k}YTHIM?L`1L2#h+-R#G5Ok`< z$3?mSYw;(*kTAh-=}B}r*XMcQZRh#?H1Ltre13-Iu^qo;zNsG1 z?jz2eKH}US_7P}FAAuVC2(+w^IA2-)fFM%hSK=GtW+e?PXE{RwKKP&YtD9U?Lf>IF zcoOs+{Yv5Hben&$|B>p;&<|7k7U)6!!6Py!=Y9$?{0wu z2U*~0iXZVi9?f(1(%~pLa1xOp174;A<$`lgP=6x0-i}WOuM1V6Q($OTd^|YEo(awb z=NOZpZF&5HcCO{o1+6N3pK*!DpLmYDXXYv~7K_1s6CCGakcM9vx%5KEIUz>kmbswn zf_>zfVwp`Me~n8G+il+~UPI z<$i=dU&Z;m5B@LWoMz+5oaP6V`}|=huzW2T5^#9Z!P68!09?$c+~Vgb!ox5pJH6vw10qum+sX z?@G4tVzj0>DfZLPAh^`>0l{=t&MDyQ?(pZswcs6h`}`L0PQ~wWJPgL)<2%&CA@N?H zKPlXddl|}~i+;30Kdj2ve+{0l_%GnOmdC868)3*(4oN+3L7SrZ4&bvC-wV7(@q>h$ z4iusTcF!{T&x6APnzAF8O8MsP;?O1czkB-vS?| z_$T1`ihpK#w8t2+paWbw=AR|Mf`Ma9hi@#8Um3r%Ji0PcKkgED?QrrI;p@rPi{3v1 z;+OMMs;=B$E`}k0nxT%5x1(_1&t*Ew>g9RI{eA(D0bj0oE_h~*uRqc8FlbPQli^VL zfbVb$c$4DifhRra>nDSkD_+d_mh)Xa>DIQ^` zYQ#v5pXwGTrr|kmE;!S0>R(;t;;>E~i1VxC+XgHYf2H?>sw-uc+u<&0*QN&WdDraa zeKh;!KHR>wdiiR7RnG1{_#eXUr9aB;Sv)K4{+C@^!k|S3I=~s?_<_Prpw|(IAJLu* zeW!|ZSs(mz#JSeSkwxG@6tWr)2@m-b=#f5n9Re*xgZN%2xcpX5!OMzy+qCQk>JVb844GS0xwkj zFmP9Ds)OKgaH*WX2xh~;F{aDW;4CTmv6ja#j>lUbe=Tl3$z4O7b3<{U4?e<0$DZXQ z!}imh17|zOc+gdjbI6jRuL0+f@l)+#)196}W(M5+EDmAdm@z@-)oyj*5Japz2(A@w zJ}%M;#!8Pjb(K%Il^77@t0BGyJglGZ&-Pg`G%9`X(A2DgFX@w&E{>=XzZ7H(5jcBwAs4{3Pmswi^Og zq8=;v8^X=$l!>{ZZz*>xhBGl2^iM99IH8Os$0h@}D+{JL2lk8(?_J?ID?$DrOkP%w zy#Ifl9;FUWL+OqJzoH~4u39u=TvGU&bahj+=R4G_z^hph{L%;iO}M$kPJG5qh5{_o zr5oJZ-EpWJL(cLi9G5{j%o*79HDWL~BDE^Dz2IpXZD_NTIvT$==?0(!2)B>LPgwH<)PgeXJ@Rp}z^d|qWFsz9+2oL^s zmFQ5F*aAF)k{YS`+1B#t5I8Egc;NXM8uHzROMdyN4n3yf063&7o&`Qu@#DeAD}Dwz zE6Vt1ftNRA`kTPT)*w$kRnMk^*D8K3I42hqlz`u*{<>HQ&N*6l?&GfJfl4cVJd%d4`Ml zz`?%4?KL!B8TNz2bj1$?FIW6H@JhwU3pWkTRt*ZF4;s}qR1QOaqd)fdffp$LsBlxc zmEi30KhTr2$3Z_+iD>2cWHcB614~DTf#B=``4-?w>LN|DJbp56ZF&4;d?mcrO*)QE z1R1s!hfPhogN2(OuS1WQL%+l(h;lZx5xn+!zoN^)!{y5GIt+O)_zv$2?UMxl{b@Upu>^Y zFd*2V66b)Yzv}fMI0d{!@$KI7-*M1_-^1URfG1oJi6vH&IoWW?c^g9H#7O=%^@r- zG>n1+mrU}*!1>+k;=?kg6Atf8oY>{<3C0WrbQj7#AS$dsdb2QCYS>K38P(uxMEg8Pfq5 zPtk*L6&z@wLo;}T`di{}B2Xa$Md0u|^yG~5C-h~|+waO0Z@lXrRO1Vlb6x zgu_lSoa!8UIrXPQ|335=z)%W3IrTSzXJ(novHoJc1%c|VLH@8cJf4OFIRiC-b54*i zMVxBPmB}!yg`V7ElmBZt3>f3a(iF!0ByVL)6p%YAF9HcS6-tDjB^?7jIrT?^XF^Y& zBi#OGLOl#@=~Ot7(_xx$lXxd=ul$Pv4?s^&eJwb*WAcX)XT%YBkjlg1+i(yAuSo0j zE*!GK`3)c&peJX7jnEfBUjW0tNv@*gz2mnR_Gk)$(i^(=pTlj zzp!*G^yJi+hj3T~2UcP!9LVYL0`$wE=e^?B(34Z&34I&%c`*EEkgG&U10A-9Aq__* z@*Ti=L?a&x&Z8LluHZbnk?#(UqZlu;AlMTI9=Yg{2F@cI`EYO^#mM&u=Lv^=MAdG& z@>%`JsvFEdqpD7kf5NjxY_`Pqm@UybykUbxIfJwaH}m0W9G`gW{ReoVIv4If*y(e@ zBM5Yoa5)!-L66!(^PC|_UFjb(&PAZh5ojv}DuX^l>F0uHD*ivjDYkKB^jbr*B{dua7K+p6MXh}3s zG>H7KHmjHKYQS8f@yj@l{Oe$7Qw~3XrylJu$G?N;E56Zk`SWdRPV`T9W1sMvKUcO6 zVTdThQ1CRx_pw}hrV<|reckJRf`h@k6+a3*9M4W96h zA7>o+P~p+~O99V;AzL{V3O6fS9yo6xS3*zDF?ikb_}j15h?9>vvUR)sM{nzTOalYu z^}$aApP(9AV7WZq%<(VRiIyh>WxVM?f{VA6ryu6-rB)d(g+rs_Q@~plp9NvCFGO7~Bg(#5V-@3AYDNjOFF1-3qIh1F0J0*Pwp{-2K(sAn1agoI~)d)ywIB zDI9o1xbuI^oQQHdM1-3Ly`=OfKu=EnNzku?o=?`Uf!^}o`is|faQIL;EPw+!6Fdfe zC-m7cybC=!^=qI{JH}ld=B~-+-v|d9=+HmK^*A36eCoNMa8n_2>NB7(f_@?l=Ri+R z{dp;P`q2gl8ZJPfyklKUIrilUL{9yk(7y;h52Y_aPfq=d&^H|$x&)>_=BE=5O$g*@ z5PT1ZW^mqcZoi$Y1UdCPfcL04Lxr0;RCF9V#_>N64m2>(3E=u6#7PMB83J)HD2AS# zab`f@2|X(mJ_-jK=Pvifbq&k(2- z`aHx*Om!6^XX35ETYKYU{0ED{lqh$sOUx1-3I}oq$^vhMp8N>J$vDZ6a~bsH)L$OL z;Q=`CIQ zwzLBdyOVYnQ6 za_Wn~6HjpsBEJf8N`>3{bGAPS2VNgs!K>Bn_Zr060N#Ov!&AGsNmqmi7mU-m3(o)Au*^Eh zA7)kwUP7RH6{s0{CT4;+!3$gcCmWHOVVzx z5?!%+lYa*>7>8mw3`Z%BhC@%RgV^$*&xbw&{dLd>ZGI(YL!S&iZ{wd99-1*ug##zW z4+un#_`zR&@PClt5hO7EG(Ty(yE!xx@gtT7!2;oCT@miTLHu;o;2l63ESKLOMFPYL zmV&pb_dH$z=h##KA~-7-1mm2k2?h=U9aeyIEXiL3XOGF>sG2`XK3i+4x>EibaV%bK zT$n*L+qz#h|K95@?9ekwS7Mt*wLm6yo8%da}p{Bus# zeDlvt2XAn2mW3BQW+My;7N`<5^ud=3H>JryY4}ifEm}g(mVE7!cDkhByOs>DI^|ON zeaLP0H06)q@=~g95VQF_+o%rfLv^@SRh3>kE}?4trQ=d|nAnH#Vi)dK7p}Yy)ty!q zHdwQ~P^Rj!RJd7LS9Z9$Rf`VpyqDt}pl=2*6>e5Ua^T=5aK<6O#qxnHCvgzmS~X&_ ztUTpn-_)-DwDXJV@xL0J+tNPV+WT<(!n%cP`*7QQZ_}&z!^@VI$B*P7;hSo8hSkgW zgMH~=sRub822+$F+ZyDy4%3ePJsyE(DgDXdm5QGRUaNRM_;Sl*)~0h|Xi^Rrf;TIE ziRJMPy$t%)wSJE;w_H`!x{Fd{ZU87YW9y1ov4kOO4u5YlNE#y&QUex#ULS zl0Rx-sr#q78QrN83(E^*CLK^{|xap4CQcOgMJ2Y zQ~V!rCZ;~v$8})rxBd_e01rCJG5!N#DC#x1P+M3o$2&C{lPp(bDK1-E9zT@Z3g6UF z9vq6nly2mAu0?q`aW1rhqMSWj44(Eqd*CcD2)Fy#zeTv|@GPg7FTqCFenTJ_*x{fDyjCUn8@y<}Ux|Og zyA|&@+;uGNhgiLg{~$4#o)x2|e3Ul|4$FUxbqIo^q0cY!D|ZF-H9z_K>!7byl~`c( z<~Jx>ltVoNrTpp#dJ%zg5r}t1-$FlB>ARs1uJ9YWYr3mMhUhW>UA2dc!BnD5we)m2 zBrB4m(;0`OOE#ckP3x3pbV9ZK^Bv7-TpT`owO3C?}AI%5W(Hbz{u<>o%2e z7^d|1^}!!SoEF64%dYQ2pN%-Zv$C$>Q$iCeejQLAbIqM z2Jzmd{{gN+Eh^6DvAnnbQtuQom=bM{NyJhg0f$Z%D5np83gTp-L3{_j1p0*EqLb0) zzhM&wGyZoV&>RHfWPBd_NK7E3e+fKY@fCgW)&t}jqUrJZ=rMl};BPqOsz5=8E2-v# zgqt|;BhE0>8u`hDev*oFcrOp5r7#XBAkanVF<;fb8V;o@&~<(A*@*K88pIDjo`JrG zaX9`q$60^r#cv3- z8P)>^iX7-Fl%oRe*#|#RxS5QPp+f1X(7DhT#KtlCFWi(t_*4W+MT2-!nrHR#yV(PX zQxcm%;?#myEB>T#$v+^dRfZSf(5(3D;N6O^22cCLAF_{xn@SX+13a+wKgd;d`XB22 zzqJ_5;V^T93lx#oo1cr}P@)oC1-?M>Qt&RtZx?PF)Px3&!e^L4BOH2^!zwt`!XaXt zBQK^wAN2S={s;OV=(!i9jdVRuRr=u}3^~e>37)6;G2n%Yp9)^4`03ycieCsGHYvkY z7}^vs0q;?q9T@tjUx{+)3l+bQ@g0v|e~-ejUO7Aq9{lAeXaY}F{4L>T4rPP$s@dXT zHw5HvBqjg$n>5Iyec@)ZjKx?Qck`1Y+$5NQ1Ua~?eHd}bojM2}g}(N0*MVvn1{@+0 z&H0}OIt(<1n5%$%3(NZjC0YJ6$s};z%2B^Hc!1M0`L^KZ)+}0ov2F)LhH^*+=Zyyg z?F7y{C-Pmuc^^T(8#wQTguDF1U?@oOd$u>ns?!+0bD&ICm}bIpExE$Zxki{^3-G<^IDdoBz{W+y~5j#L|jLua~(Gq|d(7 zU6#9m-y?xG^)%}_n_xhYkL{ZcdLF#;Uw;XI=@9!4fvkYaVYPLT&kV10x6=&tJ_0o; zeH(a(;-7&h{o^NI3!eFpI{$wQ!zAUf9=t;FpTUQCy zj?MfyE#NFQ$g3E#M7`-y_^qG|beOnRSToSrY;^t3WHjTNQr|yi4&nz!Q^g$D-F?3mvxc zd;BpSw)Ocp;1R`t1)rdJFxrfLzu@HqVlQLKKLCab%xX@$f#7wDZvozdM>Xx6A*FQvt8)1ndAi+~!UT+~v!_uLI{oJRPCG2Isn$k2eeNEqA92){7VQM~{o#6K>+S{l`t*Y8YlZeb{TD!wm>jl;Y3y+xy@Z!p${Yi1Fp)l^3i&${GJf z%Xu!WT728MEk`t2=AQ|TzHW{iWVR)OASf>&?v>vsZgQasJ^FwlnKVlWk}M#cEN`E&$oSAp`uHz_@-W>*~{|yt8Sk@;^YW7)2Fk-9lQ$g>*li@mlttMV8D!Sg2PLg zCwy1wSK($8Ebbq>2?oLMmJbM~r1}&3Pw??O_IR!@x6#`f-i}pRh{|H~GiIP!ekpet~ea3U}@99QYpReCXHj786MHi@_717i52y zflpApS-3ew1Qp8g0UVf^f!e^kmHun+U=P1RzgRB6x~wkw-@s+){X=vQ44f=X{I})t zOToXE$4|z7*_)o!5#gr81$(lg82>$B=1Sy1QS-`op*h0;F^eORCz-iE^hn|4$Map3s96D5jnb4OheI4{YO5Xr|zNeS`pTi;fV1Ed{ zheMa@@%Bf#9uHIcJ%pPcw<-O}&}SbuR zphj;jgP;TYR;6DLeXG)MpA)*Cty2zr2&5w8vc>p3WYHzE0_%g+3AbFoMjV!=Xhvde2F&Q8a;3Uw-dnsC$5!3&*!dzbfw;50aNDTe|$%tQj7zixxRN9n7pzPwkC zg)3kVGX0Tg1y51@1MrCAYlWNkHltAN-=Je%|1y+*N8zFmgHAZ`R_+)$WGaVKorCfDd)_Va+nB*N~JG?J{9_iD@1TV^vjjL7JQ}S zsJ}Qpi9lm;IkD7jaA;A1z6M{T_%GlcivI!L>2b-QaDppQks9Lzgqsp|c@9C41>U3h z@!*le{7HH;c)H@}7;at)$Wn$vF__u=EgHm?@g4-qQTkf&v5G$lK3?$`5Pze@xAo_2 z{2C6kl*9jlmn;4U0@b6T*rS5oPjr>5RQdzJYogqZf0h_bk1G&}ljsubAlts$^)Ex9 zmC-9g5FB5$BnN(f*jtfkTSoRp9B0FA#2SJ;#El+vWs8JM`qh!584g zp$fDXhDD11WVw7Yr7H0!^i4|tFL;aMTa9%?vktuX`b&i&ATz4|s**o1NswxL)xs!I#Hyn?F?y z=JFehO6-McdNdr?#5fpJE_jFHXCTfr#MuvVZh*c=>2Em+F9jrw@k@6P9EK`h3!bI; zBjCA;KLcK%_{-p>V?saiN*KzO!@J;>ihluKqxcWt%N73{yq&yv{7-gc)=2|OHwZj9 z!f)t~;1R`l1s|z+I(W9?;h``TD8sSfrHY>jUaojP_yWZ*vOIp_Ds(&y7MA(XCnv)p z4Y!ggL~sRow&GWU^En0e)4}M@!^)gYyv;`CM>5rXa5tF8O8K#q$Lk?uP>( zoRB{V&Id5$^TFFxoCV-ria!RP__%tW`2-AUIQ25Yli)lJlh=duSWW&cIPW9Kp93%J zjgRqv9tPep&|x`vU9W?)ybRu~_^aTZimw9a%`4+KhcLLiQQ{zY6P(9tTHXfdd7k`T za30&q*MRe}1NlebAy2(Dd;$X>BanXv&O0IU4sagb$iD)w$B~Zw8*tpDMz6o`V8~VP z+^q-aX_$e20yn2vGV|{*;CygG+i&2!U3Xma_rSm#4?6q}&RvoGUvTbn0ghOzOpP&)?TIl(l;4A18mA(u5#nAI1 z)J~_E3dx^UN>&bOVlWLVPz^fGI>^`XD18C+%b@Rl@Ctpd(%%7IV0d)>3xfM$n4%o& zz{?e1BHY|`E&}IG=MT`6qo6^T<^6*1rbbU(Hvg|M)M7Hy;dgM(YVtq9JC%L|IIkM& zH-dB0k@r6pUo6JiOT%WTx}`K1B_&S;=g^RE1zxK3gTZSR-v)f~B7Cth1Es*gu_Pa2 zdHfo_qvi1*sP22WTavkAHX_ifYR7q%b#VM|xDO6k(bnNjtLAxbt>)11a^3QNr{_8m zLEDOi+dqbk9#j7e^t>#K(4cTsjdS3n;9jt^^lVdmL6+^Yyy~PT;}PJ6r}~%ciNej* z)cmAdNh^@}YNro_yz#!n4RFX`>>T)R*+L}9Io;PUg}(7Af2m#z{h~8`{g2SM*!WWa zHE2=lX>Q4E&G#LK2{%1h@{CKsH;HbAzFq0(Lf-;?9^(H6eP^uRjQ_y#F2T@eT>}1r zfyu(n8r~i2Amke8M?yay3EH7wH_`7vC-k+dLff8>=l=b`o zrSzwRHz|H0c&p-5!P_RO=l>;QFo{c5;z!}or2;(*9$e&ipb0!t@wX7ax;H+qzdzs* zQ4R@bxE^OHz72S$;=6$7DLx#$K=I5FhC*dH2E0V^T<`|PPq$n?8&@mcdC)g2{Y3Dv zRT+xJV1}RzlZ77`+z*E~rLTj&75WG!gr9VS);@5xhY0q{04ocA1L^%55D<1u0o>_haXZMC|u6}@k{2x)*!b|DnTar zdc}{iTqYMb7293;&&kjSh5itn2A*ViZ~eug0ES`8;d1aC#ixPiDIN+pbK))>K=>6I zPe5N7qqq5=f?;}$!SrG|c)8+lfG<+~ZSY3LKNW5obi8WNzzKN%->Mw8n&4)8o8qb9 zU5f7so_wia>V3h7Dn1H)@CD=?|EpnGPJ^kx z{M-oMuJ~;5PQ@#Qn^MokY(Lb630{UixXkZxxDtjWWq22X-bSD!5NHGR!<4??xo*fZ z6dx?yH0W|Q_J=xs800F4F$gqX@e>hf5CUbPLI1V-_{;BF@cy?(?{Yn$uFhDT1`VO9LxcM%>4T>I1d`MJqli+^pAs=D!vF@&H?`W%um6pcTC<1 z&bwgp@4<1i8@>L1gn@Upboklw_(w0@md8JO`Q`!lWQ2E4S$LB2hv?%UXh{C;&vTE_ zreMKo#)|-Rg`49uIU7_BUaA(TM=Y1O-Edn@{bJ~=mHt`7?U#ZmLz5WHl9{{2e;)8X z0@W#f5Ar zIm+Qo;if{#s>e4%U#Rr6!KW);i8!U9>cPu!n57(A;7|)aPqBYMU#|2C7r2H#2R(1i z4iIi8btUw@e#K2~zt{LjOI1~fES z4!%eQdINl=;va&qQ~YD_F2&m?;{3ls8NPr+(&heGt_L5c_@Cf8if;hVQ+$g_ZV2)( zSLgrjVVI;G_5h!ycn0_a#Sa2+P(0gmx##2_!SO#H4lT;zWbieLp98*L@j~#VEBwk` z4xXZTcpVJs$}k&ztm5V1;}yRTe2U_af|o14(D5*+RE9=4EK+q$!8r!Lt<~aFLrt1&Swv7b?CTcxfy*`FFR5m`Q=_Z%^UodaZ>+ zI{3K=L=GGjfVadZ5aUGfPQ{Ca%kz(ZK@Vml9~9gVhm<0}bamkAiZ21rSNv7sCjQU{ zcb+%_E&T!d=|$@K|6eeat3aDy>`J{z@h!nS6(0iLt@tqTlq=aWjQu4GET6hkil1dK=~?a1I&d!7Jb_HTg<# zc7XhK@Q{gVSPcUYljLuK^H56O3eIx_`TO9dI3JLI2#$kH^!oc42A){x&<@Un2Kg7@ zJOh%i1?O3k{A+L?-5i(voiJozU#G+O;CYJw2wtT4&)^k`cZ1g}{)gc?GP!u5VB){v zz=H|-KbFVe2?bSmy)D1VHQ*t46w z@Ck~SfR`wK19(|1H~H^?p*Gea{C@Bz#cRP^6n_$Yo#HQmCrtM%@v?BqFYmG_Lkk>I z75^AKqWCx9*^2)PUZ8jn_>}2tCEu*jO`=)KVO#J8iVp#=SA3Xovj7)hu8eSVE*J-W zbFUubKOTlPy$0t|0KQ)F%fXYb_DebqJXP@!JVWtv8uFCkE;vk3{6X;PiZ2AORJyL4+a8tVMMz;_hixyo4eU8$X zLSG9#--}pi^yW!UzH(?ppaR8LAyAnL)CK)?rQZO32Zor5_rA8qe$uJj9_?};|Z<$nhbYm`Gf9FkRn%_qAatXKLJ;idy=N`D0O z3D@~UId(FhBYv3?cIm|+WjOX3hv!qW!KT_$JLmw#px6qFbl|wfia+SlbQ(TWH zDSf(d)8ka7KNI>ArJn?S0rb6Za^4AtO65=khhmlBb?^#szQ6bj_`Tr#M0n@RT|@8j z_3}v$47D)uQ}(Nb+xHaFpaxuKO~TElwMaE|1$e9Ct>6VS{IP%Ea(R=pQW-kLU`kr| zf*WI=e73s6C9YBWRN+Qn27Lq#JsSFErO$)D(CE$l=L6FjaA;KyWpMb^FJ15~^leJt z1bwb*(D%?Ml|(CHufHA`hQ=67CpMevde(+Oe4imhxEX?BN`E+by5c7wPNQnj)l=~# zXQXnt5rHNtelvKv;&&rKfCPM(7O!4o*8x{W%yi@U?!Bc1Y4efSZu773t0}h3XCtT@DU8?vt;1!DR0$!{5 zaPWG|S$`?r{xB?84kN&u6(0${M)6VL9f}_YzCM7bt$4aLF%UWT*_)a9E)DBjC#we+Ilu@t46jDBc1-v{aq{KZYTz z)SoQv;020*2VSiB@8Am*A27|$p+&tMB_I34;8 zN`E1E$_;+UriRuan~i#6GYy<)H^dLF2ImoqycnD(CGr{IJQ0!41P^(NrQrq`c*rE5 z1^K3|dJ2*~U(d(}Q1|F5@a1S_7IOO+&^C(7sA2?4?{a{Zcj3V^6wkqWw<(MY5}i{a+m)d7K!-V~FjNhJ)~{9^7`xOTf9kl23imCFZ8Z#4mtzTc>{De5dDW zI84BM3(5a;25!gv6Yr@D9Ovf51e3tIn~^^S&ZFB(j7|BYE)LHDXiyk@E@KmaUmgVi z2sgXmNGzG@Xy|!Yxiy@eV}Aj7`i=e)d%1A4R2MIE$N4lkR9U^8|3@l^hvCo)2j1ho zg#@`u|1tEPN8}Rw zxg{FM=Dz`kl-W^($#XmS$TFW-fLGk=^9O{R4y3;5O1%#n+YEiR(tj{r&i}?C7Y;0S za5eU6pPyvV0NKgldR+V50^sOpE z2lVTd{s-s-c9`Rz`d`=M4a#9p;iku#DnTCfDRcZGI2Za(r7wd%UFpNy80Zc^P&Ig# z;*TIf1$%%BwL(ATPCw3P;KhpnpW|Urp$vb(p<3~TYg{D?RN@1K+vfpFp9Ouf(q967 zlhw2S5@I?Gtt!wp;7JvJ&t`#VD1H}szTyvp7sYaue<2Jtu?FFd!p+#%p$B}w=_}|P zl>Qs=HpPEMoWz&hRTGie=4Y2;oc}wO!*DT}#A$HgYeQ!UH>K`U`ianwfu4_W?ts2W z>FgmA6(oGeTvgZufK=jkOzl| zEl?1whC`-G@DcR2(DOlK{~4~wg6IJaZ+*TI7j3jz(RVc-#p{4H>v zl*n7bxhs;t56<0>{6lbV-@W7iF$~;n=+F)>YqfXy`~sXyDfMf?xnh!k4bBx1T)xQ_ z2JTLD_#T{_5c!Yb+-%5y2In3@-VM%mh5Qf8&xwR7hg}*}soUjp!pzp4H1rTj{T~r#T)55oI_Z4w;Hi2G3Xg z3h+Y3ud`ep@nDl;A8vxa#Oh-vK^Y8XDo`bOh2rzUs})}i-l+I8@U~cP@;AY-KGq=o zE$|-2KLJmj>zDLf@Jz+mgXbvzr*Qi>#!9MPps}dYr0d;2K0!HL30|W3f59shzX`lS z@e1%YbJauWxiEAnhyQ_hD*hCBm*UI8lkfE_^aglFFUR=54MSG1!Ik1u;pVJX`?9+{ z`RCd3)DiLX|&ezknwzz7c_% zkeG4ywdaZfK}6|C;eCVG&@uOG3o`x}!XZsLOa;$Syaa)Y5r~N&gFaK~8^CiFf8KC& z2+dQ5*N~t93HbdbKO<1S(*Fy6wrbEmrEZdzDEZ1lbD^`JbD83rJQ}K_4n+~L_2KB$eRiaDjx4r=- z?NNrIaEM@K#2gKF>x1tv+$8=OiTTSlXF;E(;+zMb6Dq@G7{)4I3_f1*n=O~WKBTVu zGU&Oqvjew*S0GOB_*aX;^q@nnbSvOctrE9_*DC%Qc(dXi;O#ySgCDFx791pIOMiz$ zx9<@A4ZcC~#2Z})5?^r(7q6OwgqtTP3HSNyO19O@A+%G?_Q`NaQw~Mo8H!(T1IeHM zMq=Lo*Fm4D^h>}e7~WfdY2ynpOi~W7Bf-f?z%$%0&`(kNjo=lEC*0&JQ60l={%yoy z#{Oa?;6tY@IMl{CnBh4de5K+igSRSv4&p};KVpK&&n-9MC6o^3a1R_h;lQU_FCjsv z(!UA)&(L$z`W^Z%r5`ZMb-4MJ&_8zXF9tJNdX&RxIQ)YId}MPm^l9__$u$`~L-At7 z$wr*P9RG*mkf|K%!6zub1bmX>uOh)*B;fDJ{Q&(Gr4Rptp+Xrpf>$e^bh9hn6G*_> zK1#T$T&>dQSRQ|QALsO8uu?gkfIzK^p9J2a_}NHMpw^Fx(040+A$V}V88X&i+I}?* zsn#F>KR1GBDn1)LNAXJV35w4LFNx(Q|D!OJ#TtY^3tp>u6L^#2tH4_ne-C_};$H}t z{IWFG__KE%98wkk8GM-H|AOZzzSS*mPE1lf8N8@Qo&R@+p-egK3tp%A0pJaaXMwjU zemwa4UXJlU8HS!-gB$#Fz>^>FD^zH?yydPY-DKhBfo2Bu>6k+gBMv!m@Ms8!3CiJf zIFQrfOUwHOtM>Ds`>g{nRewD2Tku-d(EkGuo0Q=P7&;X10_QoO4f+)v=Xv7bckl>y zR~r5V#}O@h{cV7Or&u~{1TRp5`p-6#OFmpyd^2z!Vi_k9oQGA%CI411@Wy}+gTZ;G zBi{x*d#OJJDd0R$P(K8m2NUug4L2Xca$BTfXC}ZBOCAB|Ie>f*aBkn^dx7&{LcR~U z*(0L$7i&5UT-)hz0C=-%(1GCGrl~&|oZB&ZCOCId;k#JdXlvl6N_h~BshU3^Z^-da zKJ1>h@l3e^?<1r?;y7=T*MZ*y&aH*Vfg`I%B;*YV3v9LlL7BR!CxVZ!^)L3R;OX;y zJ_9^U@tNQi|MT^891nw9Ww;#<2@8CO3h??zd|m_Itau%Go8k+>%O5jwVupMv3=6Cw zTK5&;4T`_U1d6{W+#DeDU-geu8=&uu)tmfVlsSjFaNr1y6mE8;u2=^lM?yazdQO!o z(Dx|)wa{m(20biX^2!W{u|;HBMzU#?s}{1SVo=N z^3ug%N_RIL`26GyIAp2>6T!0;FA{Eco+5DWJay2M_m2NU7;03Y#o$efF9Tnvcr$qN z<9(6bGcU@475D{(}*ML@M#2Q`*OJa4bBCv z0h6fhara>XE9!0>CI1djI0H+{JIb@cIW%V>!4}e>O?^m^W*a&n7_Y{7IQXz<{W*~- z+*!3wufF!6k)Rn%z8v4uzKfwa%GnD>q=*NpbT7T)?Cvd1hgLX%c z6K-?Y>jae`S-5FXqw2t6&=)EFvCs$62D$u2a41&}C2;6e2_A*MPU)Y4zE$blp@SU-Ble-<1TDTiD8;P(nQW1ow$Yvafxui!O*pS}tXsmh_$I>-qXdiHoB z^bw_R1W!|Z72_HbCGL*wV;5mx-zr*!-tm0b>H$zi_3h_K~81&;~^mhD@ zgF}%j=`=VL$2gd3UjtsE_$yCXZ4=n55Nl*{{(!x;@^VLQoLKZsnEgpGM4)DW6WLe za-}X;4(Y;;LmsYso`%nazEbHYf!8R0C3s6LH{<_b7}mrZgx@6GByL9OcpWc>zFp~; zLBB@nzkz<8(*G)4)<1c%6Alqfu3hdnm56Qr(Y09t*_*lhT@_&RtNw2%T;7|nWU+KoI!gC0M&B1FFPXTXGd^hklitlB(`N+Fd84iL&(lWnv z+2HAl9|NAL_^IG|il1+}yK18KmtJ28!wDJw&FDqoyiq}cf%*WPhGyRoJPXdlS{7rB!P~>le+x4cm{$hRC8hG-fT>iw5 z=R3~DN8X*U`i8yW(53i+;0Y^y{TSi)q=Y4WD2i7IeUj2ohraW5od5ag zRSQyl}aC84u@j42&JonLr$~b;|0)HDE&Lok5~Fnp%0XPvnt!+Fep?G+ls;T zAVWE1IftM`>2sk^Rr+brS1Nr7eVx@y{W+Qs3UY1zUh|A1hP zaySVNQ;?Wj_Yrf7)*(pRiF#uP|)k(GE9YjFnY}QtL8ypsPvCPU#H@~ z7s6q>a`*xcop9hsCtJ>QJu6ZAA>gwVA12&%tUnscIW!LXuu(aThhe4S7a&l!>Ond5 zYn1*z=nJ4{;+4?1J3ZVsA3~p}^yT3Bir;6rIsca^Lk%1%6@Of~=~)+6I)35p8t5C8 z{!8!{#eWoTZsXSrxAo_J{9ZLEsdCsyxN%5raTTKe0_e$c^#zl_bD$@`1bj-AyYZiH z4e~26YRQ}lhtjBnjdc@vx#AVVO@%JQ(D0$vGUyj5eNzpd|JN(STX1Mr{1fm_#lHaW zR(w5p(p&!A`V%}oREB?H$WeT&2i(w1QalyBMDabrYZTuXydJ#w`Wpqq8s(5Gh zyxN%Hs)a5wug=pD=*gu8#j_?eTTIN9t($&;0G^&gbCl$9nLw_)SIjgZlgBBYhKx>G`EFiBc}% zQb#nn0)ZNwAujO`u8xBr#D=N5vr`{@7w~SS9}d1j@l5dS_xy5=c03GPlpz-mN$>j( zr-PR(ej#|J;#0w!Kk(y}2saySncZMz@!*7e)H?JF-ao?M4ju=04yda9v&i!JXB|&j z9zO$~5gzwU!z^B{)i`aS*wJWcVxgiC(;(z=g*hkuwr z@hu;6bEQY|A;L{bSK!RTkC%>uKH(ET{y6aDPt?uR1O#eCAbvOGY&dj%>Ia$w-rnx> zsy_HU#BW9X3~pYltb_cv%ya(OH-p#0fusK>c#C?K=xuOzfckgASt0T@Aq;F04Ifz^ zKe;}!JbrS`UgTCwHk6b44dHgVz}V;EUSh(Nj)xrkVmx_kfq|vwdUWVw=fF}&(9#9M z%`ZH&a>?MINkijiyV(8~ZVuub+>nI}1EOz|r4TE!QD zcX(Xp|I=bHvp0Cte@5{s91=hG6L&(N1U)vsVB7hw1IbFiD|o8n>B8;HQ^^R#FBUrk z4iV)r5xiOPBJfVduLm#r!tcNw;ikh~lGm(10TVBQ!%F4w|8(6CTwl}w!0|h4#A2}! zYcyh+5Nj3-jSxaCgt3sHSO_7+4I3d}Ar@jGHn}^GsF%aId zcoK6dewy)M9--v^fqi+DON$B_5|xEze)2jR_3&B**8 zLZDLuRAk{Ym(tLY_<+hk8kg&V)Z{g*#s^W`Lr!cQ@qWtJ67j+>Resqcr| zXzl?yK4sgl!c)I;uR;I83zgrAr+@9{-;L)hf7rM=k$kVV-xkQ3y2nHI#1NManuWKJ zFP@6GE1!dRDc{$4a0d5Pt>lYu z{BIsyJEBb>xYo4tdLmcdIbnhM04FXD?Tbsk_}tLfKHM@wUwgf~UE`+aw@%CfC3By} zNZfA%fy-Rx;c*;LvS;!1{F?D#{VE$e13%bw{BP^m)58riH*4RjdzS(N+26SbQ88Yn zybP~bUV*nLuf{t^oY#)K2$ZjOJH7`m_}=w<@e<{Ap^x)!t#B`v58(r9D*x+;fwkxC z(a_hPvwwIJA$!owP=Cd(g=}avp8vR=O6?o|&$@5spd`p0pkSp51am1{Di@zEn{0uM zP%rrtpS1b1$4B6eW(WRl?z_Sr8}BvQkz@Q#(MkgKKe$8v1>UawN4!`0pZJjSzwv>A zvF)4wH+tBfuftBj{FBO|o3Ayf4~A?-e)7*_8}ht3yhM2--lcr!z=Jn_yftn^sT33| zKhSt^ooIZ^u505N>LTf2&~4`eyjywM7#|&f)7aGn235f|p_@;N(J}pc*Wr68ufV7A zf+YDj;YFkQw*OlQl#d3&n%i*MV`->5^tI2LyFy?4tU1gaq`?J^gKp%K-~7}9d-Tc{ z$)CK$d&FgTy{Wy)wyNKQK{yY{%;cw`j=xel_v-rJZpXA(BQ7{ z6>%mag6=nZ&gRRE%4_D)xJ+Cm`S%z%C-ai8Q_U;=J!WwJ?Tmam95nMZLCyNBc+xNK zVf8Maqr3~xSKe#g_v%z&H3bdIhw$28-Hs#vYfsc>?#)DV-;n2;ICc~IY zfepw(Wq#|20`GU*kPPoxr-Pmkw6p z3FM3S;Kj;6#ru_iXWaB}Ug`gEhv+vG2(~nuE!~+Orai(nQRVMqJjgE~Kc4*K$dCBb zZT~d#%irdwb>#%R(FB6IiK9T)JexJxj>Tn;_NQSysa{u8*b12580Ee*++U%sVak!tA2b@(vtB(nqZMT+T<*%7U_ z?J)jk{F2;&jHtJl@n9qlqoM7HfnzBCf#U=l1 z^4~W3;rPoOZ}xaFH{-k@Aj!dhH^=4Rl2|M*2dVfJT!vbF8(fYF<97b15s*2Sf&^U7 zWAW*sul-6tBlNXj>Cb4kuaNR$mPE|Muc|jPc-d z(aNzWF9{!n{g1kA?<(?p$RFS%VY@ZjlR;ea_pt7JO_TO^W@29ox|JV_4=O(vkBxTQ zIW=_ilOPk_JCf6l2RqiWX^?LwXP8@tdK$6;*-rDb@ObamZU;{r501(BckQ7hSMtxv z_ole{Kj86G$9QmX{6S!FY{2*i%k0n%DUZR2l~2RHZN_w9+SwIPP(H`F>EApvRDnzi z`jj7oM{MhMa4H_9{9HUnc`2T=?cVP9pROa&qzZ1w2bABB$Hu!G)QG1me;zLwaeH!l zZxC2C60q~X67N*rhj%Og3GY?@H{P#&qW^@Q;{g?j#XG0Dd$t4Kt$YuBNcn!ax1HNg z7Vbx?!0`l{l%I~bD=)yilwTOSd7{p1ksVLZyMp|Fo6q>0=nW>#sugy z{LgY4I)govmyn;xFH{@!>pFaVlO3VU*dX(wZ2RBU1cD1unQCa}Iy{|*9_Lt*j~_22 zze=@Jv<|;K_&L^K&TdgdR8K*@YUt5*__M}?b`GH(`QYW3t{pS})HF&=Et?zAJ{gIGX*AMK3Hf4&OH{GUfd7c+r{D z=Q~D-9rL|a6htMs=kX`&@b74-h7FS6OW5KmJ3{fQohj?^MC0aU9p|l~q3P_|JPJ}& zL%Hkl)5C_wc_+}$RNAQ|KU1}H+gKkNe^YcH4b9**lY{6j3g)YZ-dl%%N;@fBKjawN z=xIAbMPu3t`=9hLfnX=%j0Xo%9SzA9?O^g3jcF*z&sv8cPdl%uDO>b3-+!uB4P8e= z+Ha?!*VG2RM1F&6XZbpO1??-IMVt*W8%&35RtM;i}D=mRzPbI9*f?WAj$ z`9GY7PF8zXLP5W3=<;>=^|W)Ux)41{{;+Dte|8;#*Jx;K8rm(GVDtAg`O!PLr|WO) z@Q7#Z2yMYZEtl%ujGIfo?&C*wt=BfPe*5O06voTj^*_Z8~wTD^p4r*bXI2v$n zmS!0bj=wIocF7~ZTy4+thw=a-RoI56*~phh)x-#Ywp8d^j{a@c$r=C8dR{MdMK zH`Yk|rQtzle&fx5&JKkHa4!SzR2y`Z@n9rA=J1do-7Y1+TjgIzem(i|bkIb;@9pRw z;4e|oPJ#UV&1woFRsQeBgFQ>a>-aq4H!XI@#AU};<3%=KE)1UcJAq2o!TQhJJsx0# zFb|AO+RR|A#j!Z#5oFLDX#9aVPf_%`eyyYTe!4pjV9t$58xAo*KzQcfbUKhB_%2 z;(g)X7i~l0GM8WAgQ|l8<3R`6JTl0mU`nfPCuNV34YKo}NFaAK5SGj`9&AwiOk0q_ z`zi;&WE*P6WrK2X$rnEk&rBKVI1J^#WERH3K~${*=TXqA{0h8Z`3-o?EVqMdJVp6~ zc$Cka$(BA$AXE9%c$4y1@d4#4@T63CgFeHH@R9THM*-EC;%%XZ|tm2ZU) zE1!-h&vn}Iy;%e@-GFxh-lO~=JmpBIAuk8dQGP1kd%T-p6uS8bS-lh7z!elUp6Gf7 z-mLsiyj6KU-md&9yfg5T@izxR8-cRl{CGmeW9Kb(S~{{{+rRKc_Ofb!?@MHTMIy@?P0$MseCu=1~s zoBqvvr8l_+zfcgReEf1dbaBcz#q*VKix*b9?eBumzg4aO=MX5XatjW@`G+`X3ycR-96545VE*r>Ahz1=;1N7U`7?N?@)o>Y`5SoY!*2WCei)eGWnY+Sj>gfy zk3u(BIt~_ze1gkCD*hRscZB;kP#-P_o#cOw`!W;~_?CdY-6Q@zE^9jR0bDN0;%jiZ z^oswAbKx32|9&SRS12hM#^r&z_&>Njj}l++wcsEf=gE^i@d>y*P_u6Ok0c;ZS*2hi zE{}7>H^Jp$i1?GaZ_rT>TkN7NHo+}u){ihO;CvZ|Q2bTw7 z;``$E;fAQWoyO&XgG4fLc}y&R@N41v-#pahK3)QcQXu#D;)mn%CW?4AE)OWg=i&0e zLHt;J3waks0>=}Ohoj>2ad|8xz5ti^EW}U6b^E8|@;qQ<{tF1meZMrc5SIrI;^*LU zTP}Vc9^71t1^+D$eXTe8eedEhu=YFs`Cr+0`epr}z+3ZCUt5>O>T2$G6Th{-nl<1e z?iDM(vo1@w8a^g}(2s$e^}noe`uJqdZv(bKUUqYN1oGN1*5#U?!SCK)YIfk?K3Z^J zxMSnJ3U$qY08jX@c`XW@Zdf)Px+t9{%zw)hd?{PPOI$o|krJePEoeIpAj+GyQ$2PhhoM=3FT~FnplTQ{c zCO=-~-$H)gO7+8FEfl1vf*0|0O`f@~`ktahd-$1coFa^Z&Y?g7{_b9&e1t zJn4Eg?lrqU6^~Tz&mfSX0<-ZX0C_fo5 zd`qqW7fQifZU-fJx$?z$tMXg$KIKdC;Sp#48wixX=XU%IUaNdL-lBX3-nznVr`LFJ zfokOf72f-qDW2%RY3H(26~r133hGtC0p$0p{A}`byY0)abZ}XiKhCSU+`TWj0{7*T zX*MSOyOKbjdi`F6mngp$mkpJ6uE%AM#c#yBZ9AjqUnPNP_CN}5#bwXLZx4N~1%-D< z=xeVh`djSFw_MtL!%vHw{=1*I0lAbGu?~3d1?zHt*Rard=|$`Ex?ayV)U;Zc3r;Q{ z_P_2W`^iMvu}t>hP2=nN=34`DdX(^S@fTjU1v1p~j>kVZL+7Q^P>tE+e_MdG$;g>5 zWYmKHz81Rq2ZzitG&=q!@CJdxF8ApD054YlIbNy!2fRx8A9($!+x|D`uxCNzXdv9+ z7`$2eG(7KpcS95K4&}S!UCQ_E;Q9Z63LHkkpz>Ti@&mWy)A4BK=i{-;eZ10FfePth zrQ5+Bc&_pX@iOKA!|Ro|;$8U2{J%wDP!)V=Ja`MHVzu2Md)k;^gm}wNS%DC^G^)qVpAfoP|5vEMW)xH@-xhCH zo`iQP-wRLq*zNcrJU8%>@i)i&JOXX1AP?_Qem35v{8GF}`L+1K7!UieB9QoryQTNy z@t?Z>7{2;5*O%c*pS%77UZwoaw^{#psz5gdQD3+XeTio){~51P{tsULo!d^-JNB4p z`A$9m--^paSnx;Qiuu{5hWdhwDG$ zIm(Ce66G6q+PSX@UB=%G_Z9@2RKfOm!k=!(JK`J02= zLL)eyi}*ajrhnUfbIjQf#y7L%8vl|Jlrngz>vd7|wj@vB! zKBlY>O8I8s5$jo(sVp`h%nJYV$J>TvB=RhK4;T-=*eNd_y}_|#{;oD7@o!76N5T;@ zpC|a+o%_e|#D83W)+bP=0?Y9(Z;rEedk@bT@A@akgZqW#Rqpyf^4(yI*Zz9Q#L&lk zevWEr69V1Jx5j&w?}$f4xEr(w9;JL=JjVLy`FALROjU3!-aNtW;56gm!X)0h94mXh zXU}hMLpT2*Jlb*7{~-h#H*yP(#haC%hPNs&!rPT!j&~}*KJei4KiyGo$4g8gn9Dph zmoL%Kkjihv3pa7wc^B`DcKs84!1(C+o5SQY0yUet1%2Y1yZ$wvw1w+~c!u(EE9}%% zjJoZA69O%xf#59jrWg-KBK1RiRLdRDLF5l@>2^F1kBfEvSbRYFX)9R&$8ivay_)|i zqT_NpjwNsx4W+95dh&}@{tEK5RempC;j6$G1Ui%t;3?DGJ^KqUQod1_9qI<$mSRp6<~ru~ueH_<$-m3B*8l}FH6DyyzdHRg$*)rR$KZ8)_-;d|5@=Ed=i+V3 zOYtt{*Wta&Z^u`Q%lzL@U`PVYStFh_)7{YL@qFcP;DyRp;`Pe?J_3y@@Dtvw{BJyK zPj`bRcH1fIp6z-p-jnM34#v%t`Cd0iZytM`O+m)qZox@-^BmXD!o9h!UyK*;@A@J< z;=sUV{7vUK6DT>zEw~4-I@t9`@a9a{oAIv0U4Io%KXQx*{l7<`;OH>{o?|7^7VLa`4H~$~wrhoH;V=54}%Fbnl@~!ZCB;Vvo@hKczdP0WeGT~)D*rm^V1e6C1s*rz%>SJPaz+C7XspM}l|O~IC~w0Dl)r~3 zl4UUfiLh*M(@>RJ39 zyu`^j{l7;*UPh(heZ1Z&Fz*-Ot;#>b<$@;de1gj&R{XQTgU|oSqEP~U6v*OJ{A;|H zvq1b?T+R;h?{Rrm6dwrP-rkRnzlp9118d*kU-G-XEtjR3{G#6CKdeV_w2R;JCvRXd zLb7_E9BJ>S9e#d2&&BAdfT%>cst*jx?;L@xwe^2zdi8SrpKPnk@@cRXjPM8Y(PC<5|TQH1wDE|k~JloA*?_+zcv?-r}r=O#i1Caz;&T$)>h^L|M{gJ+I7^FNJ1??}L&2D{=(=erHfF&?})7GGsuo@d5+;R4s88)k z3|!#0vz1REy4Vfuh{s&y`b<1gdAjjngVOM39)LEGFV5NRJx;zqc&Y6mm+Q;+;S*2u z!(zA;>}WjbAnOX7pGXH)}9NwaQC*$h{j{}n`Y{xOYh8*&_ z?Lb_HBFlI%1?e~1{3@Qhzf8Wk(>T2AA zGmHnX1$n#{)G|yrlb`Xpn|}{pru-4S-dBNU0-efV#fOx?hsQL!9e;}FDPN7(;3MbX z?*!UZ!TNo6gjOq`jK?flg0-rfYt-GFy6Ua33>uU38vUaS0^&_`ds znKAFY(9Q2;Br}&1D5gN>Sp4G9*M5`i($LplMAv^}7sb-PtQ#Ku%r2tCV=fr~B7UV| zyWea;mR8O5oHdM}XNN8&m=W_Av5Q^u$*W>-sGfHfE=#UBwz+mUn=h}H113M5|I5uD z{M%aZfpE{pdofQrbLQ3K70R3Ns;AxjR^!2is}AR-!~3C6J`Su3exjfrmmg`1|I!|e z;_R@Ov<~0RcyPML_SmIcA_d1A4>qXnY2R+CEbA+1s7-CqO?Zd$Tkwo#caLwwbDnYi zUc6LX&c8xaT{8WXDNSO{CPM31H9n{*ZnUDbgIBtcxjtkum+DfUa9;jye)JYe>2=C6X;L{3-K=HC3uhW z#dx3cTkzFmJ?MX_2?R%D&JT7-WieUuwH?y9*W96AjK?d#1y51F6i-v$VBGXS-pf#d zXG|d2p!Uyf$MR0=P5pL*BHP^!s==d`Ka3|Ue+o}+SL^>*2&AimPP|L`$Hs&6yW|u1 z)-3WH4#wBr4c#0s8FA)+I|8*M0ek-KhPNwE!v~cgg2%k!c6=f`2@;Tpa?Hl zemP#L{Cd1v`4YTVc^&SjzwK_(G6IW~zkt^%f75s{1@&qQekDKc9k>1Q-`c5(=nQ@I z{EH^g{jOUu70-On^%;1L^4WNg@(es;#n^UC|3?u>asuXhfafS*h!-g@!Lz%@cHnu7 zjRzw%#0bT5X>SbjgY|!&DtKNxQ2quD)$(d~2o3#0eu>Io?>pP^0Qu7KF2;k?zQW{> zj=!P3DTw^oo=)-|^V2D)QXQO6emeQm!QJH7tNdDgaMW%8j}jOj4TSslEFST`JEX7S zQOdjUIOU(=`O1Iz&aD5#1p;%E7k2A;TdlTNz?${aN&=GSlRJNJhc5mDcY{*#I^_o% z587{Lgrxl<@;iK0a5;ei<=5l!E8UKl;7Q%C*WoFvTwjJ~;Un|^f(Zm$nya?-8w#pE zbQ}5=Z~4ge@juuRYEvGKcf0O;Qwdak>^3w5Z&p4V&-=v9&%hTcKMLD@nD3aKecCv9PM@F*Qoquc!Tm6@TR~=#^3bvCINZbm5$%WBR_XH zvY`E)$ucekNg(t+{=j0bDU zL~(9LPxvX^Ab&K#9-m|bUgAG)2YI+$l4Z(H!{f%=OSSlUc%gD1uL@np-&Ea5phXqj zh4(9e7>|r_JAOL!ao)mR-FHHs#XVk*!wn7kf1ZHcrOF<(;^|`xOz;)FT={Zb)(6tg z>$t1~#5;_e{>`sraLt#%I~2(4y7+szyhez>kISo^csCx)tE>1&xLLNl9|!n^fGj4Z z;4{2iHPnaqD*qanC6~1GEiRYvk@tVT4+CpI+ZhOb?PojJo3{mn_ZQ{KNF|SM%lEJ@ z7pT>^Kg+rt)Wtk)|Jt8z-=33$LS9s+?QLD=elELkDlT&``S%+SHb`#2%QmqEFVC?q zOR@Nkt-rR9bzd$Bact?s``V6WsA2CrT!vaY-eo_VFGu?+Z0I@otn2MrumFD?Kc_VG zCEG5|-q2rThWXzfKu!7CUbT8BxTn}Qc*pv#&%nEs?}_&)-`~3L4XVI_6y!&`9UP74 zMY+BJFHl~HcPYOFubULKGv*?6jR^#cj1m?ZnG9Pa1x3+r$1Qk?@^-vRc^6(Y)`R|g z2{exl7+;NdD*qktSHAulJ7ojPC*x6@x;qeW-1KiwB^B6(f@I~%c#-mb@NVUY;xU`K z9Uq5hZgz^bgse<$HPUTnNJzKjS+<<#iT(8CxMx6P7fI#j@z)t=Xc#-lK@lNG0 z<6fNG@jH0lHm<+t6Ud$B20oPn<*V@m<-g;Ll&?Q%kBM64lW~7g1>y-LOm{bE7d%t> z-gu$%gYin`Ie5MG(ev*V0}|`?0+tSguUGkj>Kc;xPFr4D_@AGD8B^HP=4)iJcKAw zf!io3NOL>BA1_h93@=yyB3`ZhExaSmcRToq!0-ukaobm}noUY0z<9XsT z|I-K*?&o%}8(yk>AG|{OVR()5_+ zN%>xQ#X)1*5BfitK;77Y@ni5-<)`7j%Fn|y4<6HjX~)M?GhM&Yxaohqm#G4GQIM3(|C>YSMkb2+>Te^wTGzn|7QdmRl$#VtMb3_A>|YQuv6K0sN3--c+O$s%zqq# z`B@S$<7WP5;Q7i^@j~SX;l;{xB>!-?{ZoAc6)I4Kw<^B^Z&zM{#~$H!a3>zGydL)x zRp2QC70TQ2D&_CtHOhPOI^{p$4c14`zhMFiN4k5k(VuoM)0M~KdCGUh+m)x_wb^6a zH~sHVpwS6wkB+}N+It9es)BFvUgbl0Ope>Z`onh0s*Z6z25%U3+y8b1+D8N7>6eW6 zE8iE-KGy9Z3(w7U{YboC`ANg9|7(wT3l>U&@=NeW<=5iP%5TFLo#3{AKVIjnz%l~8 z%3s7wPIMc33s0Qy`bT(%@^A2Bd}RKABhaG?Cj4dRvg0JTgUNWG@@cqtvYWpf9`CyE z?L(l#4S0v)r3>7Kj+cDpXW%u;FT@*^Umdzx|M#lE%@lOzxg9UXdzC+m4=8^Q_fB!! zc^yv)d}RF1@xGEk{i$xjmw2=CHF&%7aevz>>sCGqk2-C%{jmS31Y+_>1Ht*XGoGM) zFFZy0!FY!9WAIYtr~S?PzxoWfvc)jv^JpOEV2cE*yl(*sYLznS4 zBmEwMHdWAz*PP>a@B`kUd>C(0zL6Ka$z}eP;ISU`A4|YH*X>|Oyj6J$9$n<-?~kV{ z&&KnVpKRRpZ$6Er0)-Sboac6MDc+*I9PdzmJKm$b4v#)xt^c1OP9uQ~8GD>|C~A?B;KYcPifj?^Zt3C(x?`bMb}} zw}T_`4&^7|k(apn3-Nm8m*9TxrEbBs1d5g4hSw>-ACJ1sZD$!ito%hhrZmhSJ^$V! zkZc2X{LTMV zOW(RbYP#I&OA5J`j(( z#r1i3j`CCR{#)JrbMb*&)ur@u0z<0c2HdN18@dB;QT`C#r~FBLP+aE!6#@~rxgETV z$0+|4&s6?Bo_)L9&YyUma(~11?OYbAz?OKK@*VIdhUgQFOd(U*>unQ2In(;!rp2;S>^wTXDa_0_vO=W z($X&kT2;YN=)nQz{{0#H+8@*W#(V`g_*A5PoM(_vKd$)HI&aPRUNM2LUK@~)R8{g7 z`}A+D%g|-E(u>=7k)I)53Fva2VpU0Fg zFoB>0Ii2LIHya#gT^`f5@Cnz*EbDUDT+9^AJObxR7stp=J<@h82k*S#{wMhR+Z;sy z_94_ABkdI}?P2%q*ayjAZ>U0o?nO4z&Mme4IDI zE8w3H%;dwwlQy&)+O9Te3f`}Ly11_bGfW`ZgJ$+X=6+uaV*l%o#G!bq@?+QG$KwU$ zbNw^_0ylwj)zEqC@M64K<(J{z$}9feeeWg$k&n20R)Z%he|R02~dehc29d@0^M#>4&_2t+ix9Xx}_DPN8!C|`jmDeuMmo89)m--z}9 zfC~H(7MS1qP(wO?q8*8ZXWWL?$GenI#)p;1r{F9*?Oc#iUNX-N4Ec(?Luyt2*R0sjF4)hh4=-l66i-gOI>5lC0wgl8##$$0RsnZz&cX`Ia}_V7*YSuv=`|wibKjD$w zN7xBAcUpJ~J~ICkqwQ&vrV3(lxgn8;rr>g`CB9AQwT zL=ZQki9}47{SVg|Lw6S$dt&uih>>rYreI0*?uSSC+#`7p zP!dEWJ@{`u6abe%<2?L|gI3@C_@v+Z7Wvh1DG8nty z|J=W%(AR!v;QWv5b9H&Bn?u=x@aeEQAZ3Xl&pz)pf#9*UJVec=;M8pE^6XQ5`=hMO zqfGHWTpmq|KXkOs51%v^n#LutaGnjw6GHLM9QzzwmMrocnVTJBU6w4e0|y*y+mUA@ z5zO&nOQ!Xj-+_-m-j>C4?T=^w?mNMj$t{{(V5XdCU2f6R$gjrbPAP^T`~1K8Houa! zW+KlOw?8TD*B@D{9YI5<+kkg-f?Z0Th(BaJoCu!r$bLM&;NSh}Q~uq5IBl$(OQ19~ z{r|=WM*XIOU`r=>y*zf8LvIkzy(lvz@#D|5`JKvNz%wr%lOJ4ycR0%yw2loJzY$L@ z8B<_xXF#hH* zJ`9ZW+P`+McRNuK@sZomu6T^{nRtToR6IrbK0bjA71$roQGPI97T%@&T)fXZ<8P**n82VaxCBq?ai`!4JX-nHc)ap*yz1kz z?U??n!hm_+-|x=--4rx91)g^w-u21YhCJ^fyhY_V;2p}B1s*(t=~02FC|IrhIeb`o zD;}jb=v6#U`5SnW@zL=&Q}7OfG*!@rXDMHW&sY8lUa0&FymZuU|NR6iMgzfF>3xsa zDE}F6R{k5_u6!78`P`kd4Y%SEOyn1CV2iEn1teMdcE*DXR3aCg*l;sFFDuMn`}%Pt z?c}OhYK6<9zZqR-u+LcCb{C3vOsYor6^x8kk%$o$_M0hsr>8lu5aCTZo(s!S54t9*k~2F zgMv8a_uz@j@5fV=*W>BRAH}o2Rd2yQK_FKZJdNioZ^4U{zl4`6UyhfH%lyAdph^N< zSUT}qJ}8@DatRwvy@+h=PSPs zZyM`C|F;u}{>|<9emp~YBVMljdAvjU8+hrE+x|-9rhoH~n5#e^1&zvo!rPS(;xWIw z9gLf5FGQKjH^D1@SL^>N1UgkgBEIMkw}V-DmGb@Z2IWWMZ6nV7A5Eb2FSmmQp^x(_ zzj4=w1>{$${Il@}<>%vV$}jc_^r%27KB)XkJnCb=&`R0==Vwa0-&}LFK#Sk>lNw z+Y^sdJ_k=$p1uw1|11?akb*qrhvEgwkHm8$+zpx^y18FabH4!h{7u|93{N$I;8QDU z8`_34d0h4|9f*g+WB#WBU%ipr@iX|K^5yt2J~IC+2zV3ShI;WV<=-0*mfOug+oM|U zgkra~2VH^6-@$m0-|6O?k6@TUu*ZuikY_%R(2%(7@nd*}>fkv#$QyJwXoq;aK{YCW z598tbzeE+(nn18YEfm!8MnL5>+mN_y(5<)^<&Ipf@nDZL*Vqk8rr=HT@i)P4 z3QAPL`0Z@RNt4_TqVW{vQ}G<-Gw`A@9`-+*K>L_Lu(26gQ;nbvkl2Vvv~dXc7(FGbURpLJeY!RMpO>cmyHMQgf8Q6s(J`?tAcOvxNY2qe#3K> zPngazw4<9p8DBKkgZ`%xs2>|Jz8l`7d>?#J`C)kZbhqOp@CM~a88`i#Z!D-l4h2KX zkHg~=-40H`vz4EOmnqM~i)ZZPz6E=Z2?R%J5ib%uGnsc#P&&iy_#yJM$&V-hJ@OZ+ z{9f{tN3I9V|HMQ)XSJ$eE4*I$bi7gdEaSlr#Ex`ewl;(ecAPvlkZ3E;&$9cAV&G;c%1S9I;d40OxekfXsXKJ2~W2^dj8EO zkf{m|#PgNU!wZ$4f)^`47q4*K^nX5q1}ETo7vhP@?g(9t&sTmkp09iPX`{$v*p@=u0;MMI4$e~|nl^4mEJww+<8AY!Jw1H0e@#z)8B6wM(ps0t3j zhm;?O4=X<%_fp)BFTi8>8gbkIl?2k$M*`tK+=OQ;zZ=h1{s>;B{29DK`D-(LJ4Ed& z@ID1S%DeHHx$cI3g%2I*`XKHd--=e~8<`t$4u^uHTOL9_{)ac+x!AYw$wXeeb^nirs+MjF&23jxSQ) zg(n~DcDxcVQT}D<<||lbDzGLDjPqL6J=?GNx5|IVKR(gDl^e$8y&}#^?;kupcn@jp z`L|wDa8QiC`z-|%aCw(oJQ8o`%_#ASxW^k0;+x>|4oTo)|Cq zfXk9gd?7AtJ@IpJds{B!Z=&ZBklSx5C^jBkV(YnN$|oV0k}od#_mTfB`SQWTx5yU{ z^Mn37DR_$l`7r9A6o^X)f8%mjD?V-)d;O4`QSk^|?)}6!FmC!cpM2n^Py!oKAWufb zHx51M#Qlp7eeDn1&3(mw*iJr>R8869Hv2DRn}gS`|LX~~69_Mj#^l9m;;XhmF1@Mb zACAkVdIo-z@!+#!@`0p2J_`BBa_jPTe1Z82VEEVmn(aU?rP9H~c3U8C7_{=?IUkp| z(F=HfQ1iNNM=rh6&ZowM4U#vxySe`!_TR7pc^537=Y3N;Y(sJdl!i{mKIAu!4{g4z4I{>T+k~O335=}W*n^=ZS8jCFmi}aOefhT!JkANPJLWej za@{50zM-3E)0?>~vbp4Usr(GQ`~~UzIpRZy|i3`4=BG9kER{lisvmdZu&QmaL;h(@>&W~ zRl)VR45>79BQ7H$UWv>AzklGe8Y8KNC2I2)HCjmICuWrSk!!#A)U%RyR=zh^w?SVsC{e5r5t z;NMQa*Ng{G(Q7#-+9{ZoY!5DR*h|Gz^W3u|1J72T9lCjsW~rLv;|XY=kAJH2Pp5+d z)jx8tXb2dCfCU+wi^N;q_;|6U4e zRKfQYv{E2*yyfn83K~^@g7Kh(Zk2xo`E4ry#30`{1p}&JF$LYK;1)WF{LSuxY)}jN zt5yDsc=Q?WNOa&iXR2pZs|d_D0XeXO|9*uRDPMyxQts_xN2pr)#(2Z1+xd?+f#7J* zypfKBdh<7Zrfn$oTz7*~j0Zy<&q(Bj+2)^@C%;DJFT@8faN8-F$up{m3*EqC3SyMs zf+r|nil-`XFdkm>)s(FyKhswQeFWw!|A~gmR6|oz>LiZYUM}c9VKr50^`9RM-SP9RBjutC%?LGN)S1dBG#JrvZbf^R5j zRHt9ep7xk%Rry=uF>*m;E)$Fg9S=!6GXFnDI9`^ES21XIV@x;-+`f7S?5j(~3`xw=Nf!G@fe| z;BsB53&Rug66c>|SDBUd`kmH-7+^OL8MyH1!gjFIPs{fyB$K%LS^O z{Mb^vWB!<*Yz!wU$IQ*Y-H?{GSkoFrAyrF#Oua`>q_dM z;rhTIc@DXTf=X5J4+W97U?hL1y=}*JDu0&opo4gozkvK^C*K@@rxM7ocDMAL(9N@H zb+lhhe&Zc({?+7n|87@4G7=T!N8jn@-yC@G9(9Zg+)hEJ^1JYC<+XUO@(1ud<^RPC zj63Jw;{=LSK@(o0{29DV`3rct@>lT6QMdiK6Q~{ygroNsUaR~)yk7ZAyis`%-mLty zy;=Xas=!wibSVEhbaTa2bNnayad)|M?9H(UX@c?zc$#117HmWySrtse)0M~I*~+)V z^OSFc7vUrGzdeC6Rgj2RD&GaKRlWz_sC+iw>bmcx5$JRS-dwy_`9b)A^22aXjc7I= zt^AnK&H6uH1x}zKS@{CIOnE+@b+;HZg_%8(m${)vvlsDm? znu2HWNaZht9$ebhd(qWkhIrS&yOD;(!^@@lpGv%4b$lxxcaM9J`b!D4slX$6zw*cMw54uC z&*6Q_+l>c1FnFKMuVCFUai4I6d@r)rZDZb3->%8Rg!PoJfBD*!-aXlL?fL4H#dDuU1}y zM>Mz{FUGT!-y-cRUur!3nV@R=hbqabPbvyU~k9f@WRru=vx&9SCsC*3`*`z+B z>g{V!o9HIDp^fnr<Q>kk$@eF47^+UQO1L#x*w0^Lb2t3 zb_c{6P;YCztAndB=Y4@%tsX@|w<~g89<2X8wZ|k5#@L zPf-3Qo~*nRPcuF`{$^m`Cy=cQKE&rM|1|Wq=lFBu!NEAc-A<*vXgxgF9*p9qOWS{g z2?PcC6a>H36#OmR-xi2l^}KUJALr?3KIh?buPFJ&xZD$pU%bB`bTD!^D(+oMft+R% zxEz<$RlE$Bmv8Z_ak;{ZUlV#b|3db^*M)(#-_h*))4shgr)xZAnUn1Oy<8ca_${f3 zn1A;hbFIr=u;0(8ZhkR8h!i}zkn=vC2N4gO2L*x4H9vf_%yeF1HuT?~6EuZ8V7~Xj zRI;7k(|Gk8>!YZ3L3vbOK%{o~pbD&rsfvXDJ`V3zUyLAeefy{x4F2O-vv-7%OmD z)7=ynjJoXEEqJ|Z=Qg~!!`-oJe0AVs&%XyuAn17bEn6Uq&lMDiOUECO@4apFWkV-q z*t14l@;Cbz5BuNT1cDc#@?m?emc?hf@nD1E=s?cn3us7OI=Bc=AYc3vyg>Oi8La=) z-f@TMRthqd*BTEtw2=)>r-wJmuT}Zoc$4xk@!ofQx8r^S6`ijCf|qo;zTSa$sOywZ zz_Z_X^EboOR^c-L+Y%^{0DHC_9{-`+&~B2iJPj}Z$jv_luT<_IOQ1~!PBR`1b>v_6 zn2;x&{~^Cu<=;jA08=CR%gG;B`75lOp9$`9xAX%F%9MYBS1KRCtCjzSH!9!gAUkDE zq09K2;og!!vnoiyTa@pPw<_NkU#FdF|1$C$RsMtIx2ydB`4m*Ef=?*uRR!OXU#9Z6IK=M2kjmfQcraxJD*p)b z{pddTpg56&Y*la#1&J#ER`OF-{tM)%tNb^~kGJ`w&;Ng=AXgRqj`w}(Zs_`l+C5(M zjq8(*2QOOnxV#fG?=YJ$ZYR>r|FHyyR70oXS>L)H6yZh6FUNbnbMwpag4M3y7>t)#~XvO8< zGwU`UoMqzX|FQjlM8NyO-O_%%K>06to$~b#w;l82|yN1##_6yrV0ufk*hayO_FFHwFE zUi$ZFe%OBlfwF%_1Ht@1i}!i^h6@lmCff1Hajt)W$1Cr{o0R{21nd7!74VL<7Z7hf z+d(Nk=Nk_$AmXw?XW;SVi(hCwc=dZe(ykBWBi*&+C$8tad+->_ zUr+w#Xo#QGPg{tNcWK{#XzCKa)V&*nshi z@p9#h@ml4#;`Pe!#T%7BZrt>5e)2^Ho~NKw`I~sR@>O`R@~`oJ<-g$G`un<{{~v#} zowLaG-GgpZJX-m-c#QI0@L1(@@VF6Y{tqFLJ`%9=e;l5n{B%4|`2~1^@+t!(yi)lic(w9p@LJ`s;q}Vj$Ng3n_<}&Y@}KZd<^SN_$~T^8r*c5~6nx0~==rx3 z0dE6$?q}l>$`8aNmCwVYl%IkpJ8t?vmq3aW@Vv|MROL6|Y0B@w^OQe?=PQ3Q@L>I4 zrUI`}P_F!4yi)n6c$M<+@oMFN;x)!c$KM?A8|K(KYgGkX;%&-zz}uD2#5+ z_J1US!O=i?{+)zJN4m$vLOfRaC3w8@Yw-l-x8<<@PgH^XDM(Vj49`*iBA%=KEquQ6 zkMKNS1->D$NcnGgx$+6e*eR=1J{j*&J`EqlN9KPw0&yF{Pl zX_6|~12<*33RK1OYmOh*W!K3Z^QeQ-;b{z>p}m^2t;q}&hd+QjPkeeSmht#amv5J z)0O{b-1I-*%TR#{$J;r}Q$86lP(BSWQob8rtb8B5WMj4dKa4=BDmWgmRelCur~E>^ zUisB{!-zBgHxuX_3E1;*Dc-I8QM_0Ab9le<*YT)L+$mn^6NpiPFY!3#Yw%3v<4&+s zR;+vyUZZ>}?zgGH&IDE~-wThKmW*^6ORp7kIbhrvIM^3_Ahy&xYga(e55^d?Hsg=8@zL=&!+isRepPS>KA`*|d`S6|c=V?3$i0Hc zj=JstT>|l=fpGRe#S@i(k0&et6Q8eq!}(m$ly5no^?$w!>_9<*@|k#r^0|1W@+0vE zR z?qoY<(aI;`G0LZ&%=$l81$L$&P5EAUy7GhZ`O1&M^Oc{57fx2||MLhGsRAD_R(>O1 zqWmtrM)|{dt+>qp(*)`y5MKX0?^V2B`3k&4`Db{i@*nZl%Kg6x464Ay1$Hinm2ZW6 zG49+?$0L-_!XuR*VBPnURNyEIl9eyOQ2=m2$ZUV2k=G8 z|A$v7e+jQt{tjL>)`R{(CQv;#VEjA0Rr&9DoAM3v?3A@D-yH8yzP)kNzxmL(3hYk7 zpz{6j=*``^KO9d}ej=W){7k%JbG81zm_U;%Sd8~5zZH+z!rh>I@g(Jsot z#Cw%*c$#nLY)A#RJk7edwLAAa;E~E_;?c_I;)%+S#FKp$IEg^2@`ZSs@=Ne^<=5gF z%5TF9@R9kypFp81ScVrVe-STM{uW-X{3E=^b>I7jK(ib0e#2XpPsq1Z)2@6n-l2RN z-l=@I(9Qb4O9l3!U`Y94_^|Thac_!ytek;ID8CR-418q#&GCLUfh1LMGoGn@DW0wT zQ9M`qbNKu*9`^q_fxIz+;QU*O=PUmbFIT<>uTVbjbUS60$|s%9`oBsArc%(Xd}q8x z`CfRp@`LeS<;URtQ`GwZGy}6aUZ7WvTM5@G|Ao@kPpKS@*qO6*z!`sHyJI z9fhYTUx3e7em1^H`DJ)R=raChxUVD7r3#kd!^$7P2r#k(D! zh{sJ+>;E$eWKVMoF2>WgcYQHlr2JOAJi*Ps7jGGH=KpainC=!lk5?*x6Yo?0Hr|=& zw$o!gc(`53d(CBh3w{H?z|Kv|PHw^G_$7_}Ehqov{9QXTF;6wu640nUh z#1oZYjOQv}jF%|C6>qXWdj8#O0>KbPPvjGg3{eLK-p=j@eTXM2@5eKg|B4qnZu*Zn z(@sIT6Y#vv@J8kFc(3wZaWBc;&@?e*{a}myioZ{yh{0(c$@Myc;Beo{>PnVryzb;cS|Q34~~h( zjolI2oBTy8KND|Iek|UuJpU}#{{t#;J_S*`xf@i5rzrmqo~^tFFH!zqyxv!VW&-WX zm*a8C?gn+?346HyIi93^08hb3=KpU3S*jpvp`Dr>Tcw zku4Ttnf4Vz_J?et5qAiUOd|>*7D8x*SZK5@Tbo9R#X=**8lfNIcg}r2SI=`kZM|N< zuh;K=UDrAHea^Z6JoocwaQP02_%gVBSHyGO|8fN6TPjje3U9?H9K_4ujg#y}`Y>F+ z6C(MK!sRO);+4u(|LPyb!dazn1a*cJpf)^4*WvXj3&35VPm#^K`prH>Yn}*ElbsRtPM;>hQ<)S6O`;mhFi z%_Z@ExO}llhIHm_rXBfSk@#b9`CgIvwG1`?I}nijfK2@IN$j0wOXX^IE;eYDT68=6 z<&$r)c-zD5!}43@`o<)0y181GVuZ$CtroO?{x1Qv??mZ<^6Jy<%WDk0hCCi#OYVo) zk*6rv8&sZ*`~OVr@%IRXtAO5^Vr0|%bSl?-(2soirIfv|F&io_8#Pk7&L2R&{8Ebl8r=U&Knl)8 zL+q)_^&a>l%pS-urQCoHB2&yB%P*z8fOf>C{aU!sMS%ofK_GdKJ#>xmLh_Bu^`5od zYw}ys(1=B5BsGpQ~Ii>UubSpUipB|FInPW@3*{fJT<3p_eEd_C&RpboQvN&_1)V66xqJWxeN^xy@_$7> zUXM5%mFvSS>^U>knV92qmY59{2RrA%-6#}D;1UE9$*+bdk>@Mdd+g9^e+K#4l>Z#O zzQ)_o!14Dw0u3f0+v7CB8_74ro5;U}=f7Ytx*y?%maG2z5h%6-j$L0p|7I$<5e=~y!FwqGo?ZAO%JtObjxmc@{sqLf z$d7oDp8szM3dmmR|9%FKR|UcTe6l z-B3Rk7hX9zX~@r}{ELy_PK&V^`FWJT{6^gWbKr3lR8T<`yo!7!I`(6a@o(Zf9mubt z{O^%J!$kpJfjOh|%@Ea5!35=cBz(yCVIESD-$eOm@529wcIIP*T)7@EML{<;v}_k% zfrhTa2IVBF?NA7Qn?<9dgRMcCn7(N^3Op2 zyU3Rv&h_%u{eJ=#+=7BU+MpVA;HUgIkiUsGs0;aNl>a?ELwn%-=QzKkp%4tIZ0UrX z%}8WXLsOLNk#J}YU4Z-rlz%xqKghlQ=kFw-=Q0l+T!uZ9IbMPM%AkgHe)TT=HFy){ zueurc|E&~w9|fJ{pDNdT`~!{9a2&?nlpmp7=l_m;xmuot{N9)7{{IXF`l+GWXy|V= zB(IupMSgg#z1r{Gg_pwPBwyzLAp{a6pvP1FJp=cXzp7mCSs2~Zbs~QOCc(?ep|pq zP<|D>%X1ljHPkPop&~To)8nuHzCb|_HS{C$Uq!wg9sA#6MlO1#y(SLand|;zR6y^+ znP^Ck`*Tr{Obw;)!Y@NR`%pV2$X`J1JfK|lukQaTumTOmU~$PSp-pHgpYl84h2%fL z>&Umm8&=Z&|KBR0N1_vZAd4~PRx_kc)X;J87V;$Jx}8R}%%-b)>~Dc2pRV&q1m;9unTQ~qA=ZKfcOj^hO7dV_o~n?)oW zbdPd9W#Y0yCGa@pi$4ZWAg}RU{rkWCPUlMqq@8R(#eNws&xoXhSK;z}P`n;4PfEpC z!STc-aQwZEfINDUg4OVHJYo@Vg4dI;gEy0}hs%>s(~jzYBLclt&nuDb%Z7{gdg`K?q## z0VV%GaJknL-vchUXyW08-epn!o6Xe0J}BrX9|g~O%|1HzgUcfs=^zp=w`k%A!b9Z# zUjpM0kaM{B1h@}pH1TM-pZpN`4D!R^a;+Jh|058P*KE>399-@X#E*f?{lEBeaCy-w zega&su5k75e<2{(Zz-4xm&>d8G`O7G#izqNX^)fPa?dFFGd)+o|06et5;zM5a<3m$ehyV7&} z-Ey!0Wz)=Crt+*N5wAusKGnPfDyLX^9lruDr(_@c*#?(Wue^`YrrvD!{%r|7OZHw0 zs+x|1QLYz|2avsZ#IjJm^{NZxiKrhP9DBFfAUTy5Apd&hI$z!wNWzW78TS~M=YUmc zCuW&x=eJDP9LMtB?gBMLJ9}@p)EheWJHd1rErXZ5V&CgMtXyBdtM-}dJu#`r3x>tF zo6C1v9r9)VT?7gwfGxcnUP4|5uOwdquO)v8K0xlSLLl;0dk>o7iR2%{7m$AqFC^a% z?;-!ixcdF?H|&moLqWrvwhzC<+$p6WWS(Zp`}*f7*LOstSK0X&!K26*z!N-|@mEbO zLBLN1cfga$?^mwpI1?_va((5UW`o2rlgK~4h3=KZSXYmui!=GKf^1@|AISf>Hhy81QOTU8#JN_x7B0q zxj$C9-hnjAp9aq)p9Nnq=$QWu1o8$0X4bBR*EZW5bRE2v{5E($c?o><`*u5zx(LKm z;5m2&`Rnk!^>#x|@DlRP@EYXuo{9Je^c_!Rx4Q@yEzYu|JE8sXcz*9d8E^wSXC7-+$UP%4~ zyqf$)?fUtDRGZzwDirjRH^aj|w(~!RN0WaIPa@wAuU8%zf3@HT5E%H(?%-c|`scQX z--R1`N8mc;yy*gXTznhwWFuYrn8P_bxmZtN+pt z+=7C}t+p?N`@XV$IXsp8F?c%p^YBcU0`&-Fldpm2k$(s;Cf^D#{Mz2o9(esX#s}wr zI|A`tcEJEVjeL*0&D<{_-ydE?J_%lJyX(Xu5WUUr_+)qz`3!g#c{;q1{Bn2&d9LT` z`G4rQcE`7(Ad0*MoJe|A--bVf=yifb!_^b8ajKJvc><#(^9#7r{Pa*#WUQhlT zyeY`N{`(Q=2ny)q??1)nvfCYHzx#cZa(&tDq5P@H55p~*JSCrp{65OhD^}0{_2aUU zC>VT!fr0@lScwjrX@feDAKGn?+z-f)q7B;b9UaeFskWjXHu zqbTq_3ZlvXfOnDacAuHD>fP)P_Juc-Pk{HjyW0gvBG3?K`^n1naU6lGnLJv}Mt%$B zUx)m9JTpEBi>MO$ZO9*-{})lvjsoeR9R=Og!MDioMgACc5OKd5iC)Sdr(Ewq7#`uE zef9kx6ol?!@A3I4h{3&^Y|t&pA5Hm%@C5Sv;2GqVo~!%+m_6-|UqnF~c>_F)d_6pu zyd7Rh{w=&!`{4Mi;p;=7hYE(5njwuCVQ**z+)q9Zo=zSMj|>mA-MiL#pizpC~zAJ685$Wmc#wzkHeG6Ux25QuY#xV?b;o@ zkH7#Gd}&6^I|G62NIQ@YFDAbnUQ3<}ZzI1I-a}rZTs=K^os6-j<5=u*GYZ6I=r+KM zkT1STe7wB_o8e(T+qc5gJ(uxUt^I^R0TuiOuO{E)K{I7-J>j;x$0ki9EJiXq9B$0WOxC&A6`p- zDqJpF((!5Vm;)xdd4l@CXCNT2*(8<%mzUq-v*2=fD}D}Ko)d_l2bTvLgRlS65s)Vr zQg9($9#Dw?4=xWD#4m=+MN2#j?#IPU{0bKVc~?sU^E}rJ%>G;Gx&0ol&KUN^NN3pa zVUA3V+~?o%wQ=cKuA&9s7SIg?-d#T%L%Q z<1^YX$niZI`Mq#Cyk+i7mz#F8vRe@3~!6)eKRAWLtv$yYxKaj0F;hK34`w7nBv zN!|nZ$JzPY;n~O8{ujK+^Po$@?q%i_-$Vs_!ZW7X4ebxlC!YwfAfEzn2zK57iC$os zlM`WI5>7@ze{g}y_rnWMwKpgQUP*odyoUU8<*I+RCMmEO1x@4y@K*AB;O*oO!@J0z zf%lv`)%6ZrtU0F+fqp7j4R@04J>CQ_I^Fgy@EY=Nc3FK$OQ^@DQ8_DOwolESF z=fN|T2gYA5`0EkKrh-Cv5&3d>3Hf92a`NZl9RWA}*CWsw2zbZe8h97^hwyIlt?(Z5 z9(XVL|Cw)M1g=hUA{y`t)a^Un!u=~g&fG{z{_uzOno$2j^LX2L^IXU5zcA0$ot-uQ zD(BP=bB878gD$*FwocvJ>DvUE;|zG|Hsf-QD8ilEJ^1OEdTeMW`u9&Uw*zvubiL2C zso)C;$aOsf8-2lIQy`b=NZbI;#{G$0E#q-RGeYgz&h8tI_x4zQ{$ZiD7+vQ?1X}HY zb27Z|DyzWp!?Ulp{ZzOw$M)0US=ZQpj_2x;P#y*Thk_#VdGK=b>)^HIOW+x~cE`8F zbF>G~|8fLMso+uN`WC9hXBL;-+O0!=1Ld!WN9EZae+o}o5^%5oE_4t!!R}z6NAw~H zak7F6^g4=Ct~V%~@=r&89_6PYzn6BveFTq$N~oY11&vhj8ak+={CAP>qYe5A`Sq0l zf5=am;M#i}U19dPg$j;RuJ<^VI>{C3)bQsnnZzRdpN zb(*PQl~*v#`EY@KH~cm{5+kHXLI16W$B{R|lgZb?Gd-8_R}HO4Add<*!sYPudR70^ z3YRGp{|H{bm%Rg@z-3W;`MUql5Rk`@W%E*p*-0X2L6^v2to!6-2Q;;8ayWPQ=$j_$y>y>-o*+YJV?oO|!wP?sk4ZRQV zxXbR~6LgR>$sX!qm1YO}DSt2JdIvgbgA$ah{?)I7+--L-9R=ysK@K{Iru>_bUqt!U z$d9M|I^;)8!qF^KuoVRT&q99wU_OrK3>4H;!JQ~5 z9xU(rxgNPv*A5Jwl_D>m6%% zso-R?m8DDAZI!$_#a$dB=W@ce=mm1sZ?TFaJfc^UjdhknfN@<)fYVF zGAeagoVldHh0Cc_{8qS}!o_cg z%c)wt2refs?Oy+PBOqreDOd)Vqd6&meDwXOVvi z&nEAI7m;s=yFC>61%a^F?JfNcoEIX}+xq38T# zl<(|RJ=@DyAEMaXJ|)lbJj5xsHc0h97l9rt;5b*p`^c|_50Kvick1nty9b_4{*ZS4 zZe9)ro``CIU6^7rAjhyXrO}a@NV(}crW=L&zUvRvC1Ba z{oy?UH~o)AAg#eJI2fKmehfT|+z-ztKNBARw%z`m=Wzd@M1i>|Xds^lZz8`Q-a=jo zZzW$2?{O*c7y^Cd&%@&y?LDZ6Cy=j!`^i6qC&35jf2$O%wmbM5-bB6~-ar~ge|KEf_A{A_bCzE%>Q^WFM+!e6nG4QzU_8HPr#dh zvHc}@EBRaScJdAIPUC^&?=u84f3-XKPPsmnmg7_!iOC#UYo;uR^2aOJ`L&ck1NjA3 zzUn_61(_%qj}C4{L6KG9I3>t0pbp+deg);f1@9x@pk3ep4^ZGU6omHCNWjC%e}kux zhpaRsltw-ho}oN2{%WtsBalS}N5J#QPlD%@p8+oa93`)SIyt;GF*ITiehf=((J_p%w%8p@AVt~aQe@@FHzk@Dxj z3Z;B(H>L!w2X8MFe8P?G0K9Zz6vO-a@_+-bTI!-fp|= ze2+j>l-+R;Je&Macn*2kD`sl)$oGfmlSg~5?*CgTa5M_q$o=pR^0VNb^F@Fw!7;G@R}+V}c@1%arbfbM@aJevFicntX$ z@Femd;SIh($GZKWU%~x<`UE>LfPzf&J?qRIXOl<5E6ERrHraqVSgcl$B z*l+AZ=HpND7%vkaXPU2Ee;!K)DiZD0AYYz2rQ=&s|G?$R&j5VZ!(RKYX9raQGu;gJj8MN0^=;gUgHRjPb^QgUbz8HQtk&QeoOLw-56jCmQcb%}1aS z*N|*{Rqk83oU!|mfAOQHAvvMOVMBZ1aujCcAAGr}Y}i+4j~P}~cD5e(W^dfpW74Vi zO5Xqv_1pd#Je>SH_-OLq;F07ZuX=~J>%>!FqzO2Q#S?JAWlSjQkyV z1o=kgs{artodR1>kV*bM+;_U&@gMLQ^4(rDr|&rOec|z^`(5koHvxgDWV?eS;nCzL z!(+*3!sEy@0hP_Jfa3wS5vi%6Q=T zI|_klDwqn7AwLtIexBXIh43u$E8z<)SN&g)K#mn~oZI2$Ki~K}*xAMUFt6q{3Xj*J{a6Y_+ zJPY1Nz6jnkIF9kkDK|lF6 zxbu+R!LRUe@?me7sT@td4?N1Hz(EK^lOGO`B|ib4Tw!m}>F_l2^Wd5A!TG-wfjla> z2A=bZ-GM9lqnac?BvG4@)L*Rb$W8ul#2ghF>ey1XkLIr2TvsT#~ng*{YzXaY$o&#?V za;f-(GJ2oBOA};fPE&^>5(BrTEE{1oIUk&%Y zXLqm&o=aW;&nI`6Ay7zx3V0FubMPwidUy@_T6i6Kn{o9Ieo^3SFQBKv{@dpH&>NFW zA2%<5kAfGi zwS64Cl>9JwMX>Ask3*m`IG}tQyn*~IcoX>?cnkUE@K*9g%2od%PA>&+MnOOMUGT(a zdymWDN#s@V6!Mku)MmQ>e;a`XRImY_OWqF8C*KAyApZs4KIoYLe-Y>$44B0d{+2l( zbd!&T_mCe94}0Gpp=00?){3DpTY~tyWn-UyUq>-8tj1c54?$dM5CGGX7WgQ7x`p(5Bbra ztNZ^x3QR>oKY0p#^d@@>E`UdoUk=YBUkoqMJ~;kry%!)*Le2hq-MtIgEZQvN9AIzNHlzD-<>`~M~? zn5qi&XL+hNn~qz&vw`D0fesQ|?G37e*O5O1k3~CZ#(552wVCe!UqB$|L%V}oc+5w( zzYUKgZ-FO}e-2L+m-+9Oz^8Txzr&NsL*F$+okl(io=)zA=aIWp5GbHPBD{!v2E3R& z9bW&9y#p7*W4dg=(zyBuKPYfL3KGa~hbNNX4^RHi?%+XqJ$V(p(Q_GpwK85tpqUC9 z;VtBw;O#%y9dCxm|7iPGcw(^Y{(nLsDLA0~FL*Nf9`BjC&n6!O&mo@-&m%uZx#~Z} z$)~_6C!+@DlQ;;icqt@ajLL zea!#62-FP*%&DRk-a!5(ypg;I-a-B+yo)@{Z8CG&LxKI_z2woJ2Tr|aGacs;_>4J@ z_2Ts~xSV<={|L`_^87!}3k-dkec)5(WwyKu9>BYj$Ef_k%V}v|y_@E>qkgsW9~o*B zn*$GXPSG10IR54$(C{BGFxXNiJTlDoOFh@4Xa8O9`OqD>Qu)vgRsG+t0{UW8xsU0f z4)34#dJP3!y7?8JHqzc8XN|eal^vSbur@ul$BQ?|o58co1cn921{tvt= z;HLi(Yt0bV1OnbZN5UJ)4}^E`Z+AQnUVDJ;6X2-_+8({uH63SA;3yPik^fh@UMv1_ zrlA^4%|pl+2Rjw;bmWUat6Y!t5*Ld_{%xc-6ckXwS19l!--njM*O?tCq5QGRbqATq z$FJTxNyslp{^0zdje^A}z^~Fe`6#HQ4wfR{M;la!{A$Wyjr?5XB>8O7VN)G6mYt)c!p7an>BzWF(G36b;H0-R{K!v{|Cat@e^fd>-~7k+Yj}FgyZeAMkBnO zd?UP){BwAz&u-^C$tUkK?mD59?1Dc~5EgCwpYW8)w(tJFIV94_N5gZ-C&2SO4_ca2 z5GbUAli=m#$&!DFy+P-}2d3Db4sSau$g|Y!U4}qka6tJY@uPzZlwS+?A7gtSyqf&R zvZF?vGiKP$WvA?^Cj1taHS`w2aUMl=6IEBji{tIyYT&KM+g`6+pOkBHocYxj>%Xr} zzWNN>Np``{XsD0;Pc(F3jJee~(zN45uQwC!oNTuf2M;4pg!?=Xn($-<5~v^zo=lzz z&mdo@T<`G=Z0PaW&@$xb1n2AiSD>I5LnQY^8&OagT%ht>;Sp2qJ^lz@e~Rs&z@w(y z{*7|ge~7by0^g#bi2QqaFL@6<@ie=G?Vbnb9s}Y00`CoX?9W2|CILDr_rqoGrJ=vz zGSuS#z+0x+uMCE5&}&8ipZsC|L%qPz)A#PmcXo74^78ek$m~5n7#?xD?T5mB$+jQs zB9K6VQ{buONuCdLHY~CC>~we$7M<+h40t8^nV#?DwNR=T7&;Q4JYz0ovS)r=us(d& zxQs+SdaiiExa>eDe6JVH^#>a|aqvoZCIYgha>2T%Y_mR3ovXHMXESlNx4j`w+!^-B zE`mqTwEbGogO`BWusqL)?stQ_UaFrMR?lqEK_7PfMpdx04SEP2C!J+?T(OIeAKyjC zPg?BbA3?zy8r(mkdzk`P`g;N|3< z@P6{2;5oNQ`6GfCCsa)qL9A@(6XqtxnO3FV=yM8;riUM;`P)&Y0yoP)c zyq5fCcpdp&@HXW^=Re1J5P=RVSOM=MuZ8!JzXk6jUk@J$xat2>1mf=wo*T#Mg8RvL zz*ETofv1v>Xf;zdy4Y?%vK5c>vMDeb1tq0+!O`$K@~QB4@)Y<0`33ON?gMrQmm|>p zxb2JKJ>&)Oh)O&E9(X+Y!|)XN;QT*>Kp_>>Dc7qykB)*bmFowana`SzJ5C70~>?a=!&muoq`7nL`Yo|R+ML`J_%!L;{ zY3+eC58k!H_Jwd?mF+jc5uQ%I3SJZBUjNMq zR6lKZ{4qQQb1d8RHC*Oid>g!z@_&KHJ!iN7?}vChKb->MADOuHs*5a_0YDe$nBcE=~dedNjTBJ%U#mBFt2 zzXXAX;DGY0;T`1p@bs7M4O$A%BYzNHPQF69>Rq0&P?<5uWg_y+KF9GsqL+1>|SIt1O@CIOikKUtNrb5}6W}u`X4KX}3# zyMu}FO!6b)?Q4Vbb^nP7q&5cyl%D}_e&6=<;rGuncdFy z@JRAP&v)|1#GPJX=t=1=<<|WuPG&Emg9_^4Wq1eqJ8<9U-i8K_zZL`%O#scSf1nDU zPW~-Cm;6_FXoo!#&Sz$dM_aD?-wT0gE8sW>z~jjeffta+!z;;8fj5$$rCmSO>7~Gh zC%DtH{;N?rqx+G=az2wKjeLvgnOoPXf&w~5KW&Se|NR@zh{!_mk4=*IY4qmd|?)Wx%C3y+F zmfU?5fkp~E5AP#?1KzyD?sy%%ll)`&0Qon@T_@@nyP+K@C?x+Ep8Knvzt{zZ5GVZ)yMxUrNba|ND?FY2CwMmbU+_HgJ-#$kR?|=S|6>rS z{6D+n$?#h8W8jVCr@&juXTih%l=do;YB8zT}hN1y3O_ zcM(XVz|(Nw-*yLea6kFG@O<)C_~?J^cD{tWO%&)spp*Phc*MVULt$IZT;`GQ56^a{ zS#ME9!wZZDj=!T3sGtHryn*~Ic+4=ngA91&aNFlezU8X_JOmP~fcpJIcrtk@JfHkY z_<|6-<66lle_Ol0|1YLM3koX8KZm!Hcf*r*vpfDBo<<(pX{Ibod0_n2!XAY{E*1FT z)#Ov)wg0g@PJ}m-&w#fE-1MK0KxZJ}9cP!rBX_qu$c6XqVf*#)+&yi-9o|HKf2V7P zqK5)cpkVX}yP=ohe)6~AndBQhS3l-UPX;%^W8A|hT8GDG1k%ad;D039kLf;z*HixI zp6i{n|Gw}%@bbPa^SE=u+;8xtP&P9YMG!})i8n6*AFZ@FBIsY5$O}@M|?vngBOvf^u zvSY*FH2G!$sh@9=H>LMoWeQ}R<#YR;Wt)#zk8F4QN)M^}Vn>8M4Pl;#I0<{%>tzHy zk9-WglYA09YHz!pBaORGIt5NbK?V8g@OJWZ;hp>29b5zt9b@}^c#P*kXN&6*$e@DT z;JM@_o)2A+_j?{#kXU)n;fw2g#9U&nnQv zsISeTFD@PL2k%0@c%<^VdhR1e+H-#(3Mvk?hi)7^Ez0)8JRdp|N0dErqFQ2cD!jA( zOGk4#)ZB&esDtco{s&JczZjlHo@Ly1lE&E$U4eoc@_FzM@`dmL@*L0A=U3@ewb*kR z4}8W;kNS0HK%T`RDRt^Is@~uC%Jt{NWI*H#bEOT&Wd}QvzeM%3vw?jA+Z#2}-tQ{q z>J2y7@x@N`&e3w#`TzwnRPZ5u^d!5XkKsXeW$z>`vq-2IuSk??Rw7IH3FJqx5G2Ze}R{i{|3)L*xrGDc+w%$?9ZL<)}`lW*x;ODZ8>3Z znHupCa2aaxz2UO9#7Dwq;Em)f;qByaDc2p>ob2_huDQ6G81bzMB$}^&|hH@63jZ%LZNI z`7o!1Mq<8l-EsEurkxJ&i>zw>XLXxJ*GdIf!6S~CXx&8S!Bfd^g_n>QOZ(&xYS&*Q zkCX6Q;q(e+0|Jq;W{6}++u?2G+u(^u*!jP} z)5!mY*Bm*RZ_dBr-S!2{9r@gwoZa49cz0Wyq5gr@8uN=1!hPG zc7^Gsn4Aw5N`*ZpFG#= z!v5>^eCR3pSLHi9C6E2VtSvrcMtQD2cN%e&J!g|qz#ikd`q|m3)*d*AE7vEMs4C-f zCVd0>wUoaG-mZOc{MAlwMxcudzJT|Ve-95m)!v}r;F09Re$*oo;`oBx>whlUWzm@V&{t@p`|(ovP4IZ~EuO0r*U=NLi%l0imHa1o3Hk5JRsZUih&uQ`uOP&U&b2q_KR=l@kwU&N zJe}MJ&n7~^k#*AF`8|3)vM799;yAqsj1 z3-nS{UlD*;EVVl*g*TBu0dFOL(M6z>0;}N8J$47p@F?<+;W6Z2!{f-e!`;H=b_W9p z6qE1qv$>2$95c~cbfY{EaT+OqKX}f4cKZ|I<;DZY-;oGZQ9&ZSj{FRG+XHq7=fiu+ zFNF_SuKLeGAoM}Ip_}0858HkhJd?c4b9MEj5voLfDdn%wuHT{XKVo-Ki-K(Ox8S+t z>){3DpTcV&v)k{2Hz^N{zgpEh5NM%-f8cH8Bet9KLFEd&gGhKa`DD-4)h{qYrvD=m zXbl9s!|Vh!)Ikj;B0nO2qO}-LgQt?G!b`~KZ1?W})p1XOEa~7_yMwEw1M)o21NVU5 z)~o-y5xxNThT==%(eBgs(3K$&Oa2r*ll&EUHu-AL)lk!hZh*JK2j~A|G?Y&bwZp5) zzlGP5_rdGQhxg+Aahx@xt`m+xsvU6lhnJB1JXg2j)%M6uf;W*L1@9uC>bd%aQZEJ0 zL_x>1b_W;2!=AJKN_YhM^`5J>MLTc{JmPpY5`*KfR>s{3r0PJ>-!k~}X#1JZa(E8q zm%@w4%RJZ95cu;Rf;?Qd@@(~N{LnS#-5KdW3TgA<(oZD3ZLN6}EJvpwzH*&$SxQBC zVw2l!TxPBqkDN|_-|P1g1phL)OuBRhT}d_&oUv(6cF#$M}p-v5ug@b@{x0e-Fb}O~cl*3;zJ#P5JHcm;`$ozw$i9DWP@JW!!c8DbS08i0ADEHvo?$-(!b) zA=Lp8FTT^UVP|NmYZA5F(ljN#~Lf#Xj~R|82+)u4?Zw1Q=N?b9c5psZrm}yVriZ@ z(K_Y%cHxuY)s!ErT)%e{bCPMtXLiOpANk#sf05_v2XSiOw8!fb6L5OSuZCx=vh(xd zr46<(h1ZZj2=~9O^Mj7L6$tddV>eU__chx7mNZ1ZUfLo56dw6*P&>N+E(9`~f&$8S zDAz-pj3JdD^or`!Qx@W6QU0OIb$%Z5A z4X9VHpDd=YF;kO`3ufDIW(ve*b3cVQAYc3&csKcW7XfFjJ@urBuxnAw9Cr|WFTyn4UEAopd|6k=VxozuRcpDkn0twr%Q=u&t&Ls zQm%)(9{EvNj7$E;4p2M!@X(ER$4lX(l?TRO_3|JBJ}OuNPbRO0r;)$qxq2N=JFr%{ z-hsAFW`lA=asEyC$LxUwWRFjRXMSMsK{C9M{5*IG`6ciQ@~i*ByHCj<*&QtM3e<}? z+JhV6t>lI1pz0I5ojc*lpW0q3?Ymfwvd532p!IXR;5m2~`AhJA@;bP)#cpRcJPJNI z|CoO}QS4)PKzeWvXiZ*Jbk6_v5Kx2MQul zkYMti`5~s`D$37;*O1??Tpu;*v;(!sZ}ReG{8cA!A<#w*t%rAze~J!rsDt65dPCK< zgHG+c!6SlQ_rJFn2yx_|4m<3OL_unBfeIdoe7QH2{BiKn1NPh>4o@UcP_Ft{pOvD( zbQH+yl@5~Oa>f*&2`|8zR6Jd|o`Oz{kPm^|kYDi+z57&xf(cV6dZ$u-Wzc`CP*6o3 zG$X%}I`|d&jg;@~W;W;mwD0Y|?%;40&?C`I1qmpqqz*1cejDZIAm2d;d+Em2-y_KH zp!{kVfi4QXiiY;0hB}ciM~7+NalV23aMXzRqMb^#<40i0f6NZMaa3@J3V3ry1*3L1 z1#%oq2m8UZsGW)MLh>Ww#l{22U!n@=jtkJS4?SGr6$I|{rQ>;Uc{C}$5H9!m;yG}+ ziW*n_FGe5+b1Vhd!Q~7nz635O7V&(zoDalZxLjSuZ`H0peI|=b0=J_;R<(E$ypuNc zZn!Ku$zLWu$$nYB9In?^VEk28DFSkMNJC|CIV{B=R<5V)5KP%f1lAy5T=JWdpMZRI zc$@xzMS%pQ;CB@KmpYgbrWfNdM_lrwmFo?fh5Wq{n1y_C$yZ+uF$Hr`pqtfyH=#h> zsQQEgI>;Q6Rn*F2}L>*YHkiXIt45^VF~N zcb9#2rTWj0Wt-Li=Z@UN3|lgN!hf{q>Nbpy)iLls@=5R*=Tz@BEgN$rykVH_CmDC0 zCJLO6f_CzA;hp3cc|OeX`OWn~I?mpO&qq6_h-Ro5QSzjgsDSO)uEre&0-vG}c zzteMdlR+E09Qm?igY#dCKo#~_X8#Fz3;B!iF7j2LtHpSVy%^ty^Mz@(i-4aBn&9c= z>pYixAlXdES?~GKr=b;}nkW5o7^mU+P*S^jSMdVrz=yW(KtT3D9-%eEWkVy8U-P+X zNcK$L4g9(68hv`%sJ3foPh)@G#eV$0i~ab&U9>ZPgkF*%PThX?ikWEqFsERDJ1`jq zDPwGpDO-M(+TO#x@X&EQ>TNTQ(vSQTnkDZTm*&LpYBDa}i%(JQ?`%BMyng>vR(6&8 zeX`lR*oZm1C@%2whkpIwHh3N_qT*fny`HQ0Um_#z!MV=_oI>));3eeG!NU%)+j$Kh zPX4ZPeZuMY>3nrgk~2<3xCxYa0cY^*2RoGOX)ij+?w}7|L+ylLim z_32fu&&kJm1!_oX=%%8f#Bp}V)8O^w)8X;s?fhhTE%{94s{dh5KXrT_3S=bohU&j` z&xbh)*aM^LXETv+hE!Dj6F_kP1bc%P!LujOIoU;^fC`E|4-B1jaj)k?&rtVyKJ>_n z+k!I`MxxUjf7RLps$ge_$|`hRPJ7(63ty+)d)hG3?6I7=lJ+)hA{8z>aJq{?HU(zD z>kqMqZZ^C*#`Y}bdT}+M8nn1nFUyc0dW4<7+;jD-%k8vhkDwqe-Y$3y-gT_)&r1i# z*^w1?vH4VvO>D$M6>wk?eK>pXt^qGKue7hXdi9$`9eA|DGc_1hy6rCje=1w01N;#TN<{r-ytq~oVi&~%Dv zNWKSk_(*gNm;5R4*lBjhN5Kop{|hfw9vFYs+Drs0s30BQeX8BTWpF3S_C?C|Vsw(s zVw7*4KZ^XYK)&h!IRxSZ0dMDChbNLZ!Mn&eE7u*TqGNf-dI0%7l)uL)y#9(qfe&LE zKgtYs9~GRUTzAlo#U;o00_2BJw@2b?cqI8Ec$`ZC7Xd$cv2xvU!E`gE@-^Pqk)KTY zO~}6+`3GRfwj)0k`GfO6fPzdE$VeQruNjGS>L6aZ-k_(DFHf2-LVgkDUji?+-F2=; zL-lCLk1hQh1yy!|v*&2jaX;lhqFkR3nkfGPj$`VBn49u$fJwL zGOL1)7qOpSONTuxl#v*B_E6rTf^H6iZK zMWB*8$b>hNUkdLezZ@=WNIJL@E=P^{0_AE=s89c5QOLu)G8BkQ!NaD&ISBc3*S7}w z;*#Ht{7KaQugEtZbo~8}f_N0j!@CKQdT|YN#HE91<$6_5L%z<^f3uJ;Zq#wkLH-%Y z_nzJ9{%=Bo1f-w<1?SKPJ&$~G$$t?pr*QF=aJhDf*C|*14|C)qA%WLXAm?`RH{o&| zi@ybzQ@D5|Tu#;E?|JS`V9@xh=vpr@^uB#%tGRENJDg5DSt$L)xLj=HLqsFKFb@jS zarpVra|&DzZ=d)6tO~Z2t-j%$F=O}o($vY}ESLAQ%66!*doRLrR7<#3x&EaLx$_G{ zcgb6g%Uyw-SKHxoSCE7Jg`Fl}E@9>Hu&=z$QorSi(~sN(zput?XD?f}W8f1`vrljR zyYRo@d6d7~ShMu&JrA0zeY}9W*alrn^u~^Yho5d=3&+Ew$z$QMOe!Xv)+HdQ?9S6?Pr*glSP_+fVrlMn`afO zWIh62D3I2!f;%(pDY#L&K2Ii`ZWf~t1y3PAit=AZzKeW(j@apNQ4mc9-=iRsI@tF> zvj=gM?^CWfC>{CuaV=*C@)Ib3HuBvoP#~A8TTtMqf@LV^$KfP z-~_mgka!|o_Dp;#T;^DOn&(3g%jw!(XXtTxhB`Is!xBT}$m;zBE{jx7rOB$HogJ1} zc^#`~yEHY|z$4D0*UGsFM9#8TdjUL&yjZzjbVX;_N5N}e{xIiOYp5OPouO{#|6K&$ zrGgEftB(*+$D7~9 zANd)Se8%E|A77tXf#piCMfuY%W+KLhW94<3JYUO??xvVD1d3kBKf zcE|6+yU5qUoeS*zHh8SO z0V;^}T)kGN5t@kn%sKWRPlnf#AB}dx^cor*e|5G$H=TUKDk&8zRd>Spf zqtQ_4#rB3C3(q5;1}`FaXCcr(f00r4u zc0*5kuD-cLBUFR@0?JEx~aWenGkJzZ0I1j^ZYm{>7#LW8eeSj$gUHcE!vv zXLxxQFyG|6PUsc(Nadj*3<(2EJl7OT}@nSQyd;xaLrcH;-M^&Vu3*pU_ z|37%|YxV=?i{a+DmsV8&SqR7pL_$}<0~anwjrgr_ef|iHzlz?DKn#7%v0bvt`W`Ks5R`u$v5WA*TU@>R<9`O7!c%tQ?Kd>cF) zE^lh?bFi21I>`w5P;i0?IOTA8;dQBUeUQX1GK(JHlysIW*C$AEG~<*aKMwiwg6}=# z8xNX`Rx2RQIL=3CCr6Wle*IG|n zyMdvQM)ZG^y@C)Y{Ca!OX2PS$(>)*N)M5vutxJ#}NBLL46I}}As(>De`ZLX`HySNH zj)FAGuYzZiuS7df%(7469mvl^{^0z7g+L)S^fMZ2KFc&DCzi3X=8RcE`QzZV#1V1wkdLDwQblJakW$CBUax%vikDg{bWkVF0uJfHk& zcq#ew@M`jUc#HPI@mKS_27w+bSP$h_BhgvP!Z+tZCrhWnF0r@fF7cQu|daRgHA(3HIzRS-bkJf?;^hp9(tpm z8X14p$vgxiya0Mt|G6F>L!J*$Bwq^8B!3WI5bV1DM-V6t4k)jN*OR{rZzq2f-b20) z9+7V^#x~`u{}3mR0-vEEk^EcbdTR18H3wmkM#h;rPNV$&;hE%40R0UPk_ghPf@Ph*-Y(RfP6QF3jT*cI{ADw zw3Hfp(90is=kpNS$)R>C;6=s*$KSK)U8tNuqJAXhCZ*bhE)x_$E*36~R;L-2(TyDk04};4oT>J>QEMD(tYS=Hh*;p)Vq&h3G}v*2>Il*rjftNVYwSY#1NAPohw z7{zCMKJ*2~9M6Zoz?iFCUTR4j`oDL3`5{iVORIVr0=YNaCyM3D^>N&a)h_3QRmk_# zjm+Ed!UDUU_3&c&;QW7r4!Y^^bB-}5oKk8iT)Ez$u(RzK7{?*Mmhz{;8*O);=?FC2 z0q1OVunZe?D8}zb!QDUQK@UvFiR`cYG=4Odbwb zqo9@wURAF1v$3H*y*28u6Z!R&{}b|kv`8b5Gb7Y`I~_I$BG5q%je~cSPf)JcL?2up zGS5Z6xY z0#hIb$HC?B6F&jI?KFE;C&K0Mll-Z0IdO?kGwwQa!jZsq6v&B1JQ*%?DLxY}i&y+C zxU3cNv*Bi>W&Bk%%?k`Yx6k%`=(&B>*XF}}vL@uidt<&a-ikFLz8LNu_o}~c{V{Oe z|JW{5Ad5~4u7y|Q8quP1_1{6;Ouk$r#Q%ZInJ(9)J9E?y?Cc^`q+Io{Zk6aCW4qhi z<6+J{Sd3`LDcyyaDc6g!8;fxPKHy%SU>2jewDSl&;ZFJn?K22e-D$7(SKuAw???ya z8$2K8Y@{7%Q?55OZK-L0!Enrf(+OrvB_Lb64qk-<@sHpUci9`d6`oA~qqI-{hwBA~ zIeVRB-?2C+nk{X-+jP)`x4ZsTu3xf=%LWZU$#__?y+M1!i^vavyG;~01c4UvczDDz zyMt3aALg7%J1_(Jg(Y_WneZm#f#Yuu8Y-cNE=55nHIxnSS^ocYoqu4KQya(cX-G|0 zjTVbxF)0?IUzm&*VKl5CGMP$}(J;h448<_SGlVbHLzRB%SULZj1lcOVTW}bw9GZ||wo0(Y!LG*>m3}+n zCVsQhkA{9)s2s+_p&hG$JvbK*bCv!w=zFRJb1<)_^^wrI|PfN&s9VA3iNB0el7H=O88`kO@ZNnv;CvhJaEnl z?)m3}bL`2>z}X=33&BUCp@!T17sJ3F)8SHZ&UW$&a4s|QE5SLG+8^Jlb$ZrPc7?a-$&gD&B1D;!`K0$jY4BT+&aJS|0XTy6fk3SpM z3h(a7wGQ#SPFx)S4`3+8EM?-23HTS5%kP#yBot|@K%&G6S*$}&xD?pyI;7uk7(Y(-?$#M zT;3O?D)BIQ-gD~w{|pR;&-r8gDtN^zpT7%Ut@sA;+E;!3x8TdVIM(0qFf_dGJMLb$yJ1JACs|2~zOa4J(FbNjIp%{_wfCD)b+y!0>J^3TTO^+9% z$C)sE0R1wh|I%=C{$H*PKOs=Q3bf-9t_LfWeox^h@oc3(!RqCs|L6M4@=^s(0JjdL0RA7 z`9CizAp&KoKv%$_0DLSiuOCBC&W3IPFII8BwLB?k;>N}O_g6TSDTmGke9NOy_2H~lL>v-rJQCpvu? z6e))paF_xIenG_bNKmZwcR-&5J?HRi(3dLxn;z%vBIACEwF>KeEJ`t?e`2>Lb9v((F>-=OrXgxmX@ zb*jg0aA;8ueW`9gXl{o- zRp}puK2^=3_n=Sj(qsHL!jRo%kowEtR|$AK5}c2oag295&Q)Tfij$du4+~)^RSx@s zFHrnY@G8Y83OA+xOI7GX=oc$}CG_D|xJH?Fo4+UEutYhm0Iya24FuX2ad;Z&fWATL z|MYou{cTm?O1D8d^agKHJRQ7E@xj7PCDPS-sQ~))A7ba0-O^Pz?fQnu#KR`Ow!W{fW@O20d3t1@w(ky~}@9yul{88G%kgAg=qD zpznwVviesO@OKes7ZvBPHfi;)}p}(K2yt{wf%F@?nA-!FjzWzZskd6Y^WZc>p1=0p~e`{LV>u zeS-%C8t#TetLnkM;5_3}UklEgYVwD`c@7|d1iXKddVS+D7`Rc;p&mR3%ZB`E@B+o3 z1?M4_`scy9p>>V_3K)1BK!;brc@ZLi6`Y4m^4Gw5A49$doLe|~_!bPjNYL;OIQMY! z_rSSpJ;Y;M|hQzX9iS6Y_7t-OYK- z`fGz>HuiQp`~+U1_%D|8+D5h9oLe6MFm1+n?rlkY9AO_jnEdm;|TxVap!!JJ@^&xgM5 zFJFHJc)j8`hA^c6?K><1U$aGCIf`Tdd04njJjFe&%ZG72^o>1yeKYiR&~xm2pXe^% zVUuzgAO@459uDl;I5>1D{juPi6rTc~p6oYh7UR3hg#i=X1cw~ua5o%kRH@fMpRe>E zfEOtKCHP#A%lQ8ULz!m?f=%Gnif;zb>*e<>=*|0ki{Zd` z_s)YuiE_9E338#&#MnOw{amGg8v1J0ppDR1iauul3xe-qs8WGC!Rr*?@?_Vudd2&J zuT^||@U|#-`FDe%BWkdH+gG@mj0IEuXVX)lPw(vy!7T8hiq8R`sQ85^w5lz-8B1l(?DUG*2I$6%;e2aS4gUToNdr@@<*{#oz<>z?}O z!Bb+E)kH9&%sQ(1~z^Ur|{}~LNTy$s#FTkWD{|dZR@o%VCul#;1+{~?N==*Z~ z)25nP8Z|J%0O7{rUO4dEjK@JwPW=(k*DHM~^yJis^WpFc9Qwg>Hyp_6a4+=lu?H}$ zg`S-HccK3hdOpJW%jv^_20Hu$hacg<2a4I#T!qM~-&?q;&>ztA1(cJZC#QZg^jl0b zJEqj1k5Ve(;0%-p!8LG5u?|7N9qlRT$?5S7^aG)1{ATFMt=^3PS8&)}CFpaC>oGYK z^c8M;oC7^eIu?3z>JNo}EcD#a<_MSkNdXOXI2#Vfz=3n31_{WizZ3dXq34TduR~8x z{TtAqJq@34=5L{Nz(EY&srL^!TnWw|?>604h@1%q3pW+I5qi#v0_e%{{6oHA9u9ZF zfs^hsIFK{J<v^i{F*)_Ug_|C~4m~S$ zAoS$akAgm2ryNS)Ku(8QaM%bv=fus>lT&{y^zG1dPOO9;ocmu8{09#Iss{ZC2XZF( z8Twwh>~d$!D0UShr+ydVra}Xu?{5u~|0p=nK!;=CFcc1)MCH(vQ-2Bc2Pyr7(34aD zu+f|I|2Q~sjMu|~oDLr$!Eq|V7N@x$lT*K?aMR-{&~qcof!^?F{l#m4IF!JFPq(MT zft(3WgZ@nD*?}tP$*I2)oF^sWGp+4r7!=;NI+f#&QmY>otEhTi3ow_;TAiMEfMXH)o^Rdr3m&jIGn&D9Aj?Dxc9kbT@|-0M zc=F;s?4G*CMff}w#>uVeB-h*TmzD({Ngyn zHG{9StqA`>wt_x>wjMLg^p@`-QhY1$xr+Boz_%A}mP0|YySVV(yoXwS(zrmsO>dkt zbUC28!4a0n&$9f;@NcB3M@NqTpG>w=tCHIb)x7z_&3(!y@HGhgA+q({$-iCr7;&g) zD>i_qZs(V))$*;lKT|Gu_pW(Ay5^;x?y9<4x%UU}P<$8gj8s3}Zs21T-v_)x@zIWl zL5(sT35TVMp8(#X_;m12#peh&!(4%3&O`+kLtog}bRcHmTM9$DHAL%mKll>G>%mtm z{*vWM!LDcd1Go}=HX39znEd~Np}LRn@H#kqz$U$6dHlRvYkB+w=kI=X>y1NPgh0(5 zc<##308j1j^Pt4dxt#ua{;zeXz>u#T z(!q-r-wC`#@jVmpA>b8VdW`=t7#4OJT$gjemnwcRc)Q|9f%i=Fdweo@s^TRf3`NRt zuI2Kxg0YiD+EfPqrs5ZZbI34a!NuS`PxDXGmx71*u4C$h3K%k#!R>xjE8O%rXGfP{D7v-*`VC6o3f`i4#~GnZ zoR7quL_5!PrR!7eGwQ#6b4%fqBF*wI~ z1@z<`<2MrUwTM%XI3Z{6W;oEmKwHdmm1s~6+Aaa_C)`wG#tgUN@Rt4%=-2yk!rk@4)f0qw}Nw0 zQ(ptlRc5%&ez%6e5tw?+zZ~QcrAFV;tzqRqY{k&$ZS0K%~6KO;E=C)y>Pov zfb+f08=x;%`p+#-4o0?*FK1Ho@0ZZen4zBgehmXB9i3XiIf=->2j>`*{|L^xLjJSm zTL$&z`L016{|;-2zZU#qdHm(|9J$!oJ45XG%aI}dFUPqh^G5Fj;pQcN4kdTYaKPWr zz_H{GI2oK{xepTD3C^*k{xfh6CHXF!Tzn2C`L~XT!C7tevmrW-Ro) zioS(7uA+I4N7r8}3=@^ZAmJuKzDke}eWlW$2)O!2%s2IzNxVwS3@8K7HAMju=pN|I57~=CI!E^TZ`3a7P!R#F0FdYsx z2l#xBa5G&S)O1~J^+~~%>igg#;MB7icUaB?0iP_3^{&V&Dai1pV(;!U`CreE(SqPj z>lVJ9z^%i&$ro*^?j)V#>aKY*_-du^n}DYYm$HOGBkEF!rX320W))~0c&p+^fG%Nyg>EA1zOyS!tf1u3!y7C6eMS{{Gm`aW{5SxwW$++E$TvTpLu|AYK?Ed(!A zd@*?OXkQ<(Jib|XSpIXkIoeY9|E>x8+mj#@kHme+UE@;&P@X71hdxK?zXY!@@f-9t_|P-R zP5tHX7bGZ00^SP`n(v0DyvxDqhX^-4C{_(R5&9aXp8kLbDBT) zw}4COWcEh?ZUbk9Xt^Dn4JBU!9@qjHYq*~Jh{x*j{?t8{0Q)oiXRU?QFyfe z(vMSMC{zw-f=^TYeDH;eUk+ZQ_zlACsyUS&Mcd^sHY&QLiNzz~%C zJvartr{Z(KvlPD&e5m4;;JM&k18g#XF0T%MQKUgVd0e*`MJ#OJx- z%?o^fICzKR1;UepErV7(8%ssv)1c42RN{2iUySo$$Tx0{*D8J= zc;02v_%{CoFto-PO#Y|9JHn`g;m?4VUGDP+@Rf?cCfrn_36hKkz2S4+U>ld?I+O;*-HED^<^?!LYc}@7bBc?aqbO!S8ro4E++NzZbk#@y8J- z7jZH<{vX4kQ8|2*fPZUwQm}c3Kdaloi?J-taGAfKz`0xx`l z7luyg>r{fj!B;B&FL<-!N#$mU&3lJX3MNi=hOUi>d~3_2lZd<*^eid)w&2Aoek$TL z+m6NDK=p@#>y?3auv{M;Tkk(ni_h!(*rMQd~m%WwZDCE&HC{u zyR@(4tdso|oiyPKaMm>w&DyP>(}%1d1C@xuJW1y&ugBxv_xd|ti5WH#fsRRYoHGyY z4|2A52{^+}fj&dZ5p(>B+}L~4HsK+*M)IAiYWf}qKJ+SoJ>`MtDPADltg|u<8sE}; zG4!QZ`*E&z`Y^akIn={p%{9Km)8IoF`uth&JjMUx5(G~nK7Uc@N9c>Jo~u|&^fw%C zg9BgK+~Xp*r7chi_7`q?+z!1_nZN1KS1SEk&^JP#X~ZV~ZE&bl4!48nTgn09&lFF(IB`FoE;;7K=={n-PSA-4Rvr}OUWMvXOGDrkM!Mc(tz+uYmPsT57@%Z zQ%FCuKD6zU zAI-hauj9wyS=ak~19-{}K5qqIs(1(E-016ri|xb-gK5f;A_g;aIx!Qt0UYQYf@MlS z3cR-3PcRmI$xS{#6nur{F;o0#7}nhEJDd#OqWJ0Hb8qqWGr=ov_4#?iO~+Da#T-RV z{v~jzRu1=AF2B;JK9O`EI4i`N_5e5&kk?rrztcY|JhHs+q_l8TZ#Svfl`Krcc`1%_ z5-bECzpdk(G*y^{&w#V$jo>$K=k)C1Ch)^{usrM<)K0W{&_L(FK_!1&njEuBvxh;W z?V`K`H{#d)eek>*pMPjMOA_v$McD#JiHR4G0fyiW1q;42j$0iJWGpEwu1-13-JaSRNbl*1J8{3U*% zS>Q#Amw}fmej#{UEI0WpVd#i82)_w@lj3)Sr{Co_=uz+-#UBT+QT#>Wl3#9~m0=AW z>JJ$5aVE1zb{Gn}46aGPTF%wOW(L9Umd9V?e%;2Mx!BO%;W9!FljhwHY$&(-3qlx} zn1*uMr;G!8FdTti0A~-V-$G8M=FrIHw*>pnOW<4`JWTf5(ZvrrW(;&R3^F$5Cg(^b zt^()KQ2#bK$Jo7#F$ntXB?Lhod8_`cE2=bZq3wv`GU7=3tuXx2B#O`NHh!PjMC^2*+x_bT>&@w)Gg3_fUTJ z>JadL8Ey>OddAsnXUEywV(8~M9=WjJq`u+t(v$ASZoY8yDoQI#+lHBX_@!=4$q_R+ z5`6tqe@rKUXWr}c6CDqO5@k3|4EDH%s_=tf*CEi7`~5%>=$oL=M2l7lHyv0|>-5R! zz@wMpN@sb@ed*)YAm3o6#`H<>PQ{l;ejX^J_?$Jz?=ipO{L6yW;kAwzMBiP(H`qAx z^LG#U{rem|<3XQ)>G-&y=poH&=z* z0lZrAf#5mI{PY=)he5|~RP9a(BoK*iic@hFw`)0X) zg6o*izV;jJIG1rMHk=*yaBLs+KZTo0a0nP^%b`w>NhG_Z`lso)b8?@#>-U%v}@iQ;>MFR(nirh~-Kp;0Hth z40w&we=gkIqb`nZkjeig3^lO^;Xhd}?{`y+rxW^RO8*adz2d#DFp1^knsZ#oyin=yXM)+vPzMLip8+pb z`d2NFpDV9HU#awKz{4fV@D>bf6>kDx_Of5nuM_ZA;pT>`YvMxLviQc~?f>+f}X`tM_)-4K{|m;;3PcvkK%F zfpfSZj<^Z&5s;!dU%KH=v}s>NlP94uY+$o z__l@N54KeD1Bz;rwX@{v4cos$pZ~T$>o+IhTU5H)J@*}7zol@w(+-2N?>a*hx<4Kc z70O`}c!%OAfp;oCL%3OP=~!+&b~HgB*u2rz7PP>SiUx7=wS%*v=giC(;B64LIF9vhn zZ{_mA0yr0eik1FS>gW15-48*(K@t#+^WtR4#uTKL{Z}NGj0_%qkJ@`@&EBnQ*gQgL!WGu0g}kai!+xyZ04t z?;DhUEcBgdP$n8Q3;Ok;awvmCIuf`q43js0z+r>ZFN1z>=&>q;kDzZ+`WEP$(4elL zV%Tnx>p`1x$PjLZU?>vs>$%25pYg3f_Jz=oRvieT&++wPa0Lt#eM4{+c>Z^Of`#Bg zo6oNUum8d4H&`xpIorS2yUB9-h()F{EQZ4=`Tmw10WVPcJHTfveiwL!;!DA643F-A zL2y3|^~&Kv@J7WS25(h-894U?%(>tRaIOx+ZT_cVFdG8J=HF+)x%_Br0Ouqke-WIs zo&05RPHOU1i|~HWy% z`^gFZx*T_n<29=SZxne-xOpPPk>m-!1DrF6+s%Q)oj$<8WFl`lIA;*!ydYd|M8bgA ztaQBW^CcYYRFNQb$lA{(;K-BD1m_Ie8Hww_IfJPG4%|)Mv!V%_4sr=tI6CY!(p8B2 zMh@Fw3jT{7haN%8&;FYI4Lr5O=bhjgzxzD- zTDM8f#yIDqS^Ee#+j3i{uOH*MyubBN-;fW7;=g=e2tHf!V(<#Z=YlU*{379IH?6Y` zmBq)KyZhl#ryT0xuns*NhMs*2{R*Yu2)^=fzXM-@x5sj`_l7<)v0-*clFM6yG}m-v_)+>BoT2{nzinA(qQ41?Q+oZHK|& z#s+nkfAYXN1hkB|JpP{HD9htd(8mb(Ps(=l4T3YRgM4Y9YUy0?x}+n@nbiDy4*0Sy ze14wg@eMlP^7sa=3$dCRCGb~2p4JvU2yt;?qpgX{qCj0zB@UTG{o`RuK z@n^uxw)6uvfH!UB^VQ&4Tl>7x@}%Ici|lrU`b+2Dhao8SuYezdrz`%kH%P(&ZR}4F@>RlIG%IckpP(S)p3!>xG*Qm>uAT{R=odKt5uO z=tFTpDFW`ypGyzA8~cB4&*Yu!s-#I(Zrv9so(x{1cq(|A@M!&|7a3wOZ@rk?(~a3` z^lTg)>Qta3z#9}l9&sjawgX?F66_@0RBknRCLCr#U#ax-!D~Zh2w`9# zCcZ+rX=n}_x)Th`zze`Rxjsak78UcKLbCL)oz}2b87On-)WJ{#XS5H8$`a@Mz#Jj z@P&$B?t)j^;7QlmAmM`$uTe%ArWO>2U#iz#d-- zeT&lH2z?IpnHby`tUg*fi%tHQV5mV!p$}GqHz@ue@OcOLv-5TER;7OfJV1jOf30x) zDHDzj4e!E%Js@8P&PtGf5J}3FS=$sjP5ue@9E(|tf#v&N_c+*b&a_f&oI?(A*FbiY zw_|g`S(Z$sdmNnI#JFYCx(7Hf_q9W34XG%{Se zGvP1W=^jB!Uw=OS1D>vUP;Dl5{28N1Be-(JX0jA>JgMF?;+p|6(0t^RPj;Z zD-<7VxooLw%n!A^n{Rv`XPY;Cw_H~f`emY4rwcb*5%ciOd4%oGz?m*A#L<7wbe*2- zRM#g^RXf!!PPIIN>N%%+!Kpq?pxWqEUszSR#ZBE0#+H`HANYC-@9r42SAsZ06U5oq z#fkqWmVyLL-+F9%;3%T4~3Fx12vgs%l}SG);)L4SX}wSecQ`Mh1Y*`60-rgPQrcr)%)3zWkk zG1xm;#fN||RQw?DWs2v4uTlJX@V2xg{BN$F4#Otpa29y__I}UG!KW#H6?nPgH-m5J z;>WphzQ-Dpf?W#y3&wrmES*ya!2_1ZZ(((jRY%I+^{AM;TO{vVH<^=N`CY(uNV8P! zMIV4SDBcAA(*(b{pE^DySfd;^T0?w$zp(8c*l!#zFmOvnKTnMOEIV>o12dy?0u4Ld zxv|-4a4QAxJl{3%Xz&(kMR#TCd5fEGOLy>xx3}YAuvQrch{3!BUZmb}vNr-XDg8lK zpBxn78%*=jpnT|42Kb2!!RsuK*&~W!*rXih+5|~KGYa@O65IxTa=M@3KI+f&&wOj4 z&x+NX{7oks|=@#!CX)>=eyaPi7{IQhxJN-8}zwKzY@F{oX?EE1Fv>G`m3gC zx4BZcsRRSSM-K8Ulm(uv_;Bz-#YccI**P|jjQ?RU)Ov;>I2OD?@#Dc;6)yzuxl3$< zAUGL3P4Ov)o0rmuD#Iyo$WeTba5FTms?@hapRe>a;3bOR2|iai=D!={yJ2Wh4vz{q ziL=Z69qmKtS7-V?{tEhBrSB7QL);wIyZn8vK|Xk{Hlj3ePDaedU;sEL9r=#noOI-a z!1t1`+9WgoX1dRh$hRq>q%`ghhdRagusk_fs=h9JFX%Zmj5AcYsa#J~g3mBchQ23D zM29Ibu+-$IfNOnmBBO@*M`l8K5ekNV>%0l3>ByxJWKJbz$Yrc5WG%gaVag6^B))0TkbQ5?Hb~8-g zU@>^9;t}wk=ez3$^>QYI6dbU`6_VCtuSDqQInhl zCl~os;GA6CXonR#y-XszuZ=`Q>%ciD7$@sQr{|n-T*m)i7&s}|()5#DiFg-%8WKzv zZZ0{xXYVH9N1WWfevRSgqhY#q56T#KcQk*~j=lUSQP=EsEqWWgOz}p`!34)**`Ua){!Ep18W2G|ug+R?J(BOMr zB}$L;D=}QSsl-S%C#FKbQ0ZquUm$wB|8dgY1cwzT`w8xXL%mAyU+9~Z{(bOf#Xm=! z=4c$7Kj?Lz>sg0#*g?4ISxwZz&ZAuDQ;YnD9s_-fe$>57)xXnKkhWZ$Ti8dd6jp7yHyhbqd zm6pqvjJZO7HTbNn{YQ+8YVmOa?p$=Jf`i$i$jrYtf^+uLb~899DfzA7+&{=`!0Rti zzu+z-fW!MPEUKLpN;mN|dfzeix;)rk&|fpapF*MoCblRpj4 zixBy<;5?X+4}TtpHJI%*tN`ali2RkvUH+m|E=?Jtb^b?;2 zo?PMca`1G;ud+NTcu!67h2WjGyc}&Q=5;WzrL6A_;OsH^P2l(Q@gp~|7>}1R5%`|aY2Zx23&uU*Y!LaEk$X>DT zdt8g5+iJQiI1}@HIUbyeS=dG3>@i<2c@vx+vwCC9It>X>iDD!^BXYc1!oNs^yBneH zA2e$#zJuwJ!_Jg}-AT;dxgBENdIW3LKph62e!0JrjuCEd1SVEFJ_7dv)!=1UJKlu* zfORg8JO+dTy$Lpo!L0dq4AejvdOqa#h*YId6K?dW7x{b2A<&Od`lFz4vhihLIUr?l zU`yGc3&Gc4=lA$Z1S(RAABVn0>0f|;VXWRvtgqpag3>YZ&u}P>br54lovTEq(q{`d zmB?256QCcV^wWjgpRmeR4vXNxv1Eg)z)NoMD^UYJSMdjgn+7da@f)pPhWN(7e_-%F z3~p?gHV8fh*N@{qW+1hwH-K|aFw*DXtWflU0Sv4J9li$V7?Zbxb7;uF2j>`*{|L@X zkpCQ6b+){w*%7(P{PRcTXZh!}9Upe%TcOH12z=y?e)%)Omn*(I_~L3`zegmgRI=?A zdG8!~+v~t7Za-tT2DB|@n&b55M+qO2ZOA+YXSQbOhen1=)bKbY&ArJ_dII=}n|(eV zJWuh{z%y_0^(El-ikCVb1`W!v01l0chv2oh`U$QBU#@rre6`|tST5gVWGDF~j;wqS z0SxV!{j@9v?|HF*8onPqQ}GAga6N2?D~wEbR{@tU2>6{}P2kMNU2U@ruX&l7*~oKo zvSW8vqj~3I*f|~>z*jjwF5tlOt5gEIM%P+*-b%smK?lAG`k$dOLbL?7}k5->N zUFN3IyS5nenY-Kk(OCz+;!dA$6mGVfktiOs^?U?ZjU~Rmx8+H};TQPFiaw6_>k7nC z>l=CUTv;?}k-q22KLa9PnEx8>;K2^&S~zeTQdZsVr##h(XE^a0F2dywRyuf%gLM|( zHh)rbB<;LOX-SV;9LbqKX)C$Gt^3T6`!@2eRQzM%rX&R@34c+x$D^(!Ym|OF;YL4O zm2i~RBhFaXL;f8L!*9iY4G#rpAi9i;TwW$cJ0h}bzWkFPdD8q>iG#B&j8v3KpO=?O zpRaa&krP)rah-#YI{3JQZ#ww4gN+WhIrx)5p6{DcI7PD~J}$OYOQZKC^sWeMV3=*5XS#9o{r&}|6<-R=d7reBgE zPD6KbO#T-W1bR6^pijCBBym1V5T`jooK3N7tJhnl|f0`J&o7I;l2viXlNLnv{S0;#a zk8rb(G%s-1x9y!gcr&ztdIXsp)dnWq+&T;e&xFJFkGqYE95_e^pQz&O1U^miY|E2^ zutHr~_k%;JayTdf&l7HX)_#fWnQ5N+n+N@36=%NBqvKzJKnqYJ26_|@4JuH50{#-> zoPjv}TJ=`wH+XR*{}0_7g5WO%8jC>Nx{d{dpKwDEeC`j~kOcf7@GPYtYq)uFL>nfE z!IX3Y5^smZWeAk70$r4VUkyH2>9337(fUi08Znr}|6(kAA@Qqls8)ggn}DxJocZVg zZ~HexzdRbpl95r-YSupTdtY*K+1 zAdu#Z5aFAPzb(E@yQAJOyOq8($FA&V6+3{}Jt#sCxbC-l%9V7Q3e-CRPY171`a!Y0tNt=tL&RVb z->ed!2!~n~Xi5S;3vosv4!)QtxEcC2F>!4ENH+#Ek7^NUUj*W^c?bHom_SDVKKLfZ zo554Q^oQn$r|@%~Y0B^y97ZU<_0w($3KdUDzy}I96}<-?;6{{Z_3|wS7poUX#v@R< zN^lf-t>Pym&`9hDrV8foH0W0={Y>x$U!f8l|Fd9Ns~k$f*DHQL_y)x<25(V31aH&4 z5{3?CSOmUF@f*OC*#p<%;1=){#cROR6u-;yFvw7b`{0nJ_(R}B6<-EktoW1QBNTrY ze5~cHzx3io81j_EO7Mw_zXo2Y_?zI<6n_`IJeHgM>tU#jH3U!3>8w}j@=`a|ahe`5maGr3;_Xg)7 zmV6)ZE3pxg4-aABo=?LFaPC~>2MISjTAkX_W<-QAYGoFMqB z$ndM=WuMgv+?o@(eP!Jye3QVf_cQLQ)2P;4AMh5%`$qa+BTw_vthuYFER1}5=`b-T zjdiL+6R5^H)#*+(GlA+%r@Gduu1}zenWHco^iufrdU}FbygIXM;u}5IOZ@pg&RR&w!qs`q|JITfJ2yO+hPz|lIJbp6YX?gq*-z_|D-kPocMe88%a#vI4W$?@v|Ah3WaPt_T z>}$ulFw&lLQ*xxzXM&d~K2&&U0?k%|E`Y-VZ`|U#s{X;BAUODBKKjb%?E= zUk2C+hb%ORgRlWSU-4FOc7Xct!C4{lA1#-}T|K9^P=D!O6AYay!Dk8hw@8qI1biUU|9Mxrv~T=X zlin?t{8?f!E!`V|_&WNraL7@CCMDpfB2Kw#&?4w3syH_oZXWe$!yO2eia=c7s}X3n z3iL(-{sH2gggCtG-VA-E#EI5lh9LO`S2|tHeyP$Q3cf<|qrsb_ z+~qH_hWJ@J6^74bx>%eVZQ-8K}|1+G!l8c=K zUm`zJ5_C8AGi+jc=~wma4De3H&jn9wjSjIL|4U&Q8e=fMUL@R{4;nW)hoLCND(Fj; zel>WN;_rdyej80}LT!8zk9x|K;d?k#E8YoSqxhC9+}Jm(vCk21uA06Z7b<-{^i9yGbNzh^hq=mOBY3IeUw~IC z{v&vu;(sUL;lD7fRt`xoxv?+)(e-#S9vB`d+?2FM=|@4|@w3y{ngh-c?mP}Xxg8hzpC`drTRrP9hL>STL67P17C0+G z{tozB^qBlp@b!wff^UfBCjW0RuyhR63BKT0zY<%%jLWp*{lKdf-vzu@@!f<={vJV9 zho4|yI4o9tEcg<|CkQuNZz*RrdQb-aa;3iK%nmx(xM&kCJ^S2G%(g99%@{HD9)*-p=k5WhO1w^X9L zBif#}Lh{38|M;tE2>9Ai8HQOye5rFRk1zF+b6kU%fM2`*4ftBb=bP{MmpHKv?Hd2% z(4x|R{g$2pzFhI?;42iLBiyW};0kww;^B5N^d(70mZSRSpDAn&Ll!7bg3GegUuE(&xW{*DBr#K5;A2chz5N z@iz<|#t`%OujTUL9(5O-w8|~li;wU(sAO;s0YhyK&Wajt^Y?-w2c@RNwwA|F##GDW zCu4u%v6G8&a;#o{9(QZMWBaed`9EtL-*6xt3Kbt`xx5Om8hSMJvz5L8e7WK$g0I{r z^b=2kp+z~I3ZB)=*O!1VQ2b2r)ZV^+9(WEp$A3NyV`)I`$}NxY@g>l&Oz{(32EJDD z>%iL;4{KoPxvd}Q0q~)U*MW~z{2Ae9-S@oGt$V(itr_}hO8cLIcA%0_9 zj6gm6`Xg~~0$vNA6{|P-pX|;ce7SJbpaIyxxLte>eQsN*%QrT^xy9S-D<%FjMQzeec~|F5eYIrT?^w{|6V zmPug(!%5)D{ryr;2A`<-OyQ=~1*n8+hWWb*`bwq08$4XB43EOFLh%Oh4T`@8-lq6E z@Z>bV1D}J>c09WN+QeXbaI%^#1J<~bmZ?Bl;2RVlF5JW!f;hZJO@qG0(@Xv{;V=>o zUAJy<==2=qCnv!(w)cBh3qC^eC&6bc{<7ibh0tyHLdHsIWP$y3002{AS_YzG5(H1dAnoYmypgLCqdr-O4pAm0g`tE_AN?F<7a z9UXQB=OiM}vONAiV^7O@pFy>}p<8%2w;5rOF9tJ9Yfy=m@Hr2>=qfkHhk-8vUkc9U z`nqs4t9$O?Chr1V=6(`xE@tEi6Z~SiJP26>2O2iRVfIe`D(L-|3skCjI(VhxJ6Rs> z7~}5@o_~U%9@8NUoINJr)AINs7-D(+5DXKphrs4P7720(`uCW}3pXXL zLeDC20bgYGQO*WcfhTA9m8$_yRlN2sJP0XNhI%GYduK)jK784in8p#LP` zjfm5rD)Be;^(syfzUNA$4ciJgC3+cwI0PfDK7MtKL7cTJ!6D!q6h9g~>`;ax7}7HR zNjDXInc}m-mn(ig_zK0Z08if4#*ePQ8(~Os2F!>cSOT7|_`||Yg+4@uu-^php>I?A zFTguIF8P0iVUuT&*Ci}Z3bGFKuZsVI^IE``Cap6=DPJ^%29YO&^WsFlwc+N4P;MYJ z^nydN3bZXaHz?{;!8v)!`-5{oAm0I8mY@GZ=s*~js>B)KT;B||3ph6}^4-9>3dje8 zb5aX;@0R6A99US}A;QhIX0@*mgM(mb@(n>Ac&FmWgKtuN zI(S-^Ux~B8ixn@oT+aU;%5W7ED1I||`d~l7J>VINFB5Jys7!Tq`w;pHqwlJ}6z3}# z7OOz*;5CZ>1HMG@Uh7?{S1LXLe02=B`LkeXi7}W7xmN-{6ujpiekDc;H$6T?js5A+ z=O}&YdYu2qD#N94C{+Af@KVJi;AM)}f;TAsB>2QVL%#Ad;>Yhe=`itG?@C!U&;q=ER(bS1`P!7srVk2%j=O-{fpLK;GB#uy6nG0tzpZc z0y`HC`@(_in0!BQjxqTGh_h0~83}zp<^=U)91nwHWjF+ZxRui3Fw41}kjk0S^7yTK zyyaU24e$8Rh+ezgyorV#mip%+)?bzG-8F0}Zz2!A%5gT7yaIgH6|U5L*UhVzN3R7u zm<+huC2mHA?3-xJ_#Y)L?e3y7)Am5VJ5!DESqb<&@J6MdpMYN=T=Mq_7VPCut}Df0 z)^X=T|EBYC1PX@u`ll1{XTfWg{>3QwpZ~uML(1NMg15jk6mLwx-v>_}>c?pY&+Ot@ ze_zKL+@xp)FYIz~{D%a*9lUXvpZFi@_wo4_;fHR07b?S+;L{ZE2R>Kv0SWky;MM#3 ziFW}HwP80HYLvsi;B|_RNWc$boE$%K9`%l+{!-NmzQNU5{&ymHy$UoLe5K;k6Y$f( z^Y@EwkmR2SLy>2YuftBjF90uA`YXXp6^{y$>>*cJsrH5@d*1$?a1FSR@= zs8!!pcRzT!+F>6AuM-}vzm)o67y_(&j=?hUbj6zLns`7k(_ zCG`c7RjcHU6gOY&+<3L-NQ}Cqd;VbpK7T>?`t(b?=fB9@meWK0mk0Lw$X!|{s_mkG z0=@%y&k_E1v>SN3;`@N-SRS*HjE12|IUJgRj{~n(`s2WZ1N;U}1y7CTCjV?0vSSUx z&j-&{{0i_q#cu@9S9}ThT*dDdF8SpRT*^=jhuj1G9y}@B?03agZW}4Ws@)*mJT9n) zp8MdMCO4GikOyx^xqpyqgkhOV{6PZVB-}i|XvNu-bNgH9a}M%5@M9du`2QVeaBck; ze5?x8<73w|%~KQb{@|4=PI{QYFgO9v2Cr6uh9%%R!p)GqbDbM9K5Cu{eON!zFHtcJ znxBq9%^3Rv>_=S2<@c0)F#=s!v-yV^}-jJ_5Nwxok{WrKN)qt6h4e24m zP1r(s+Z#o(WqjuPPY!voYXY7n+{BrNIQ)1?@@qOWHqH>oQ!JNPvbXmiDr_g* zBq&A#ZdX4c4msm@csx2|gQU-0&$L4_c!{cGU(4lD`y#him>>;&wBiH6kDDFS0h516 z7|NByAn*e9uIo(UW*4Z2p5HBSH1yUo^KC70(x@l^Pvxm;J}j3hXXksE`Y;K=s73ug`S-HTIer=eh(Pl zg&sV*{?@_a9ypAI!#{8!XM*5M*W-_%=U0d9E!@l@a_aYiz8(4j)*$&O!+{1mOoPML zxY%+|TmwBh_18k*A9}ug`waBt)HfKtdFd?!4t#UKS8yPw!#7B<2lTE7LD2Ur*JE<( z(}bHjaWM28;zOY~JX(M88V84?mBZO^AZLP7=qE$ZWqc>}cPlYK7#8*re3 z4r}3XF&y~&Kz~3_PW@ld->Nz=xW!e7ocipR(3R+ZIP3t+Bsh@M;UwXvq|Zaob$mJW zDyh;bU+*JOhWHz**{M=*g-73i?gZbA#&hwW|bq*ZB7pgX!7U zI0w*SEF8$0;85uMLC^hQ4)o;IpA9}3dT{v;0tCv1ArqE6;XuwncZ2h`h5TM{9%RUC z!Fkjrf5>wA4icVqX?VmMqPHRBj|n%oC+)aB;W?}CH>RZV&wJ7=kAL1Xz;Zn9>8ihk zc=;N4bIp6@6dcMAUWDgBxSH|4=rV8~G`M5F0?vcU5cc3&7oWGpX%gS&|LZzu;B81I z67OB*5_8P>N!-!bJI<5LASBpPde+@*2nX68%Oieuf*SJ;UV77pL*Nh`>>phZPr#1^ zAFK2yfY&H~au-)Gy-k6kSvkxUZdOOdjqZHFw`EmBzvd9Xp-Z4&2t9}Fzl={k$A7Ih zprr4TAL=JqpMZY^o_(0F-;jWZpTkh79NNIk6#o;vT=A{`=Qb8rh;wcma8`mm#qzD# zf8rq6&KlyEO+U-ypOXGqfk#qkPzyqhzR_{ctx8Pl=c^reb4&8qz~SnfouL_}&WFSH zlDNBBJzTiC@kklxO3fRO8r#q)XV>oPj+_23g&`Y(=i<=&E(2~10TdJfu7uj z34(hQ@LI&FIMOBNllG)2pb=c0UyjDxf6^?MFGs^gg|-3E_f+~Fp?_TI z2Z6T=kJewJWx^1krA)9pc&6fefEOsf7dVHKafX6($b=tgZTrH&647Bl%j1t$2SoaQ zA+L6fwC4Cr!grUM^U0R-b7HQ5e0EihO9i(VPL2Mz;1Ys;iaUAIVi$)4feS)#l;v{o z#*yHiRh2UYtoT9b$UESs;s)_J@cgarAjQJ&3;iZ=4n!vSp|?4`EBIN_K<|pde7g(x z7oOD4jyTR$TZBMggL7`PLC4m(1e}sQ*;Pk|Z;)q(V&` z_(H{#+gwT4DxM0yLGcXm<}Qx$&lZE}LH14lqMihY&MpVnv!VoiDtN{*euat?@Y6#W zvX#T^1pF-Ue5Ef*FB6GQxzcfNBL(2)cVgE?zxjmlWyhxk z93ciuUV=by;8EZxa2Ak{7HXuS-Q9XDcl~=VLH}Mz(7%@wg!|a)<%8#H{5B@wUpO8H zP0Ha1F_iNnyWq5pW+z__%7g0O20SxaVAd8KAhtjFg)_l{@`^5e&Ue{ z_!#i?6MX%6@Qhe)@=p?jxfE8xz$uXSqw6s_n=~*1-y;Fv%X0a61}e%pLxmq<9&@wQ zH0)~~whS`WlGqP{id3KjB42!Kj#Abfzf{Ip9=}w|<$bE=z`??{;DYk_UG4zE_VOWk zJ2=zxz_I_`R^KnU(|izB{`Nsf4vDgSW#G#Sef^aQ_|@RKC;IxEg_|X`$c~dtF`j;3fj3(fjC?$XF;E* z^yR|sFMmG>2hOGY;ZUI*>cMLie+j%%@i)O+75_-MY3LI-;pIsV!4~bV$H^!AJ=;#W zaaf3k@^Cd8`bwoA557?GLh$-7jxFvq7@E2aZk5afA6n!$=o0We#TSBCD1Iw=o#OX} zFsxOEhZ68dz&n-xIq>w!enVG-XDI%jc9=H4g3PLGl%k{+$=S>>;^H|ZxY2$ zmznH52HxX1=Sm9#ogv(OVJL@^_mrK|f$k1BX+OJFRxfh`^B)Of42W(2$pEjL;!mz@ z@CL<)CEz*2&9%H4dbzE2`R{`R4NU$}0{#dBl}&XG;`4+)zqp=}Gfw{me1~7;tJ}yY;ILTfS6IF5 zhc~;~&bz#CpkJo+zksgayD zFbaHu;)f*Qhk-9s`XdwY3BtDsSn*2X_M(NM z;Z4os(AOJ%SN$dVi*RUC4&T6`O(pm~0sj#^^HjeBe_JkZ@ahxY!fpP4;V?ou^yqM7 zulZKsvz5L-_*}&^!Rr(s)`6ENmnp+&ICLmJUbrb~@hxt)^MrFA^y$TZk1tHXF9t6u z4t>95ia?A1eMC6Q4D65F2$tFv`v*86$DzW^uZslq?-2t zZ&LbH@U+v_qsHx{2Jh^a4xV+oKj{V~;F;h#NDbDyj$!4p4BX`H^`~nPIRovJfDadL8dN^hZ%{S# z{+fswQ!j6mvqd$p`8W>nq>^#@c+|w z{()JJ-ygrz%F?P;i^XVV)nu_)Sqv+aNm%TwVHg%ulf|%@?!_=9qt%AR)M!`?VHifk zA}qp?EW$7>hQ<2$p6fdAv+X|5?){<9=XKuaoa^^>-9Mh^SwP&>YzqR(BkRr33zs+_ z`0%ZW6LAI3|5BnO{^i8RAVJK(NBi(;;Ppy>oDV+%ys1ae{eK!6%)D&Dyp%g2*TErZ zfww?6`tYUTQA&S{55MhSod2_w!%A{61!}@Yq})e-6@hA%{$1$XyB8L2zdxaGQ2Kv_ zyUMT^hLDBc8t>P|T~ng?0pME{kMQA#Dc(K*Vqj=hfu{KIIO1k7c0e!lz8HGpGLBaD z&0VJqhAx$OjSsH?mt(smc+`hiSx&FEt6!;m(sH{0RjY0kJOu~odr9yNxLj%p-v};e zI^i!`-g7A@{AK8i%o(t|{mJ?&408S#hkEd63@+iDz~wY7{B3YKGYa2q`2Z)j*PUyd ze+wLBzZZuO!DYJ?{t>uLSK*(4%PbJyY`MPm;y7P++4Fzkt(P6vA@J7AgLscXu7r}2 z;bVHLZtj@K;Farw8a(zfcRGwT7<4JFh zRh6ulBbUS({3vrd5fwmx8#tYOY=J_h|GU<+gRFFsaM&h0+iB&+I7! zoRr?Tc1->=$zb;TTIF!Qb?E0Lm+;lDe5~kJ=!38F*7#oN&x2lGnt28KgdDHFkvQe2 zpDa>_PvB6a_&4Ai75|O6*)6k>SZ2X!#|+p0PP5V<(!;$UXdMef=wfe4j{px-{5bG% z#goAk6hA$HqyJN2C{hj=5H~gZMRh?D^kquF3i@W~<>L$W&?jB(t=Ri648_Xu1p?Kp zCLPd^o3u>nM-Vp!4PV7$C7K%E{2dRybDcNwZ0KDF4$^1WS_k^j9TIaG$H@baRs2S9 z8Kk0L3NC|D_%d*em7e)m2!r!n&)q5GbUS!~N_?l~1DxbuyP4774KCBnF!NVT+_X>` z;&2O5{#TGd3@oQl3xG=(2!8`y`dD}axQrFy?|@573xC(}^j>`?hWD*Q;C9($dEjpO zvE_lg z;Yr}NNcrRqLjk}#LZwl4=p6G z#=Hf6w9DigOuw zI`N+Nr<4nO8EgshpGDwBD$tF@O$)VRcE~5;AA^3Q(mx0N9_Z8L3GWUvn1!Vk4swN- zK9E~NxD@JQAHK+kFD7mZT7j;KM427aXwVMyZ=A3hMuKY96kY;B~y4axU7uA zzXX>tA$$k8^gX!i?1VuUB5~LSF4Ir=58yJ*g#Tpu0B5c`@%;k5^u6fYEq8m?WHJ0< z4S@%&zbp?tVC}Iy@PPFjecsc23_=QoD_G~F2l%A)+o^QGG3}3U$8r+a;VK_}S%?yy zM@J}g@{u)vBl!3Y%;kg=4gN53lUOzzN!&#R)h8v}|KY)A*wBLyOb^6y4zfJ3B@VGX zuqDP?9@r8$(K{~Y6%>gdi3Cx>!EQi_j4jb8@ku_3XZa*PmAJ04i9esXnKi{X;t8)T zy<2P`WAM)7tv-Akc(u}h?!&i(H;P{7-%f2X#iYMo;O*kT*l8zjRcl zt~B{$$zb}dT{#>Nhj=75_kqk`7W5rTe=YRM&_`Oe<5WN&v((#i8;ILCJeyD=S%{k9 zkfa>G15Z}`cjBgnntRubk{>*nE0&}5lfZMAs`LLbFw`oCB=GHu&joK${6gZUK;fz- z?tng_`^66Q|7tj7DTg=UklgLSZTbQ9MbOI{xd-|=N*7m zgljBZ;!pANp7|FCLkt3m!wljkam@of{p7i3HT1Dc{}S|0xmQ1ND7Qog^pQ3J)_OfOmSi>&%8h)@liKI=Jk9!c)LyI~IO6xa@wy&jFXEUHG|{)BY!G zxERvmAWN_Ci@;?C6n+VKihB2bK5^5PYp`O<)p0TOmUp*5MOz7nr{Ex8BK8^_giGQ# zpnp~A+n^UN`rn}60=;=+Wb+?5oJXS=#NlA#rUpAy4U(Z3F8b4;{|$P%jK2nozBsY<8aX5guX`vkG7?Jo)bfdd;v?l^nl@Qf-@bQrggaPc^t zxM`s}=w%F@1HEvoH~oJu95%y2ny3&C!X?4&(0`)z&q6O;^v^@T6M7jFEyO85{a!Z= z;_xjT{s5OTF?1BySh(ni6E`*Phl7b!AOU*eqCXM(ArIgaUb50HfCCxwL~Q=O5)KjI z@@;2j&p;dbwVxhF-YnpN8JeRyFt%4#LG@2OO3_FLzA# zJAi8}T=YZ0<*+I|6dcF-V}&~-VUTmX81}bZF0h0;&gjzJQS|&W!kYI9_=%TBd}v$_ z*HyR+HXfgxl_TOVM0|=~nK3unDE%|`U$DS-Q#Q_=v4`I zEKKy_CxIsxdXJaMKKwNBOr@VkoQ9R_q^#iy6NyqUgF}IGxXp*(=fhWlH>o%ec(`n0 zlza^gA-8&K_BeQ~;?IL8DgGvSrs5xf=k?|${}(Wn^fnOxp17HLIcOo-9zw&-xTW7B zQ~C(-u-m*9hz5^Pd@6Cu-`|N;hM90kQT$BsYQ@vRn{M|ezJj=^KmjTs7iBA<@3>vv zL@DbrcoxwI!FLsT6IA%{b>P8wc=a{lq1_z)|0)c{-3Dr5`g>OrDE^rwxYL_p7kG%` zyTM}=|I76;^dHTAtQ`hgP9NS!lX5ZX+grek)lY|qfHxiGy^0$K?#kejKqFv~J`+9) zTwb;i9u8in3Um;7jpB!ZH#6^#eM~%C`!s%VZOaE_tD&0w=ua`1U8KiL| z;d%zRG_Fjbukkjgtda5wyed3~k;S|OaZ>PDMcUSkE%SH4Q+DTY9hq42&4pQPaAfg} z!q--|5jO>u#$Cd3oFkrQE}e8Ccn-L9l2qVXaDG#U&N%X_Oh@VB3A8m%tKoQWU&zB& zzPM#NwS8YtMJ}>^LN~(H{L1v`ER{9#~w<-PeeQ}e& z7KY%vy)|e6&t2i=n|=5eNucywefT!wl%IZF^d4`57BZNoOF_+K#_o3zcTJ1Z?@!$5 z(^N|&LSJ>CH~t*xa~{UgUi#)bI5a4S8-4gv@J^+_#fRSpK4+yA2>pK_4C&nl9(E5A zH#I9l&E!KIo1xE8`cJ_N6#o{ySn+ljh7x7iOWY)`Rb3Dr!Cg?N^izo&{cF&NVcKLs zA6_CgX2X@xkM4wnd<|Y193o0Dj-mC^#B7En5;2<~iBvJaLd@6-?~DsRn9H1~^h11j zD0otdI222-F4B#1_V9)iOhmEcL}8zD4Oz z^5L_<+m!w^*T--Mar4Bc6Ap5r^&IrV(LheE4}Z&tHxf53?Ixq?j?;W4=UjRd+ z$KW^%z*`i*9=ucWd>`(DZ+xJ4V#g^o+&uZwhTGv#ryNQw@7Zak?@Ph+6TAo02f$_j z68#!*vk&&PKUphah{t*$4(q_%)xGV5q;SI#i;5rX_xxw-q^uk5| zJM}UB_jI0N3I5&@Y4(DSGMtNE9 zUW(J#dGcNz^xYoX@H!l#AN0=G_lTRW34Vk}uYCRdpU~GSeZR4+4~1UN zK!+1Ihq4xx)ShcM-^6%NO$1YOWqD*d2CxdO*2eH?L9;Tq9P|IdI!f^x`) zL!CH~yZKuJ{qag)34No|KLh;ViX} zatI#JHONslK8m>M%XFnb0s11PzXJN~-g?vj*TJD)IXnV~!rl&~e+v3`EWJ{JX6TER z{yXTKRs7HixIC;<4hNIL^jR93R1zc;H#Od<^#2EayGl?1eZA7(4Sm%k>hiD_4lT;z zEjSdb0<}XQ^rUwT?S(#A>7yrd1tPokn155rU}_wx95Ub#)9pYFKz~<4pQH3;&?hMU zqtGWReUnQDbIwnJLmJ0-4vprL3J0cNfbW|h4xXhF#}hXdOUCq*M^u+W?`A8992jyG zzX^e&5hxNRso$h~XnR z$mkXR3AhYW;mzQ(`w9ONd^!f5@Ezc0GwW%8vhIXIb}ez(1umPD@E^cs6B7OtxNJ7U ze*u?mojB)jhe4)?IQ#)F3z6`@z-9Ug-veHxYTN}b>xbz7i+0U)qMwCO4*ML&yixH1 z;JkTA82ZuxaM|U=G8kNDjqsu1$u6do7=~Lz;PE-k@_^&BbAaW6r{~L_;nTAmZtHMb zJ&^RhPs!c=pGXF?5LIE`XW;O*&L-&LQqU?N{v_hGZ004o1`a<%pI+@*s$J)AGME)= z@uS|O*w{(D(v^4}oXOzTiccqQH!Z}GpCY`JxT#q122Ly$YqW9b{4WNn+51SKc@qNV zG;^R_yotU4;at!%V3Oq!P6BV6vGAG2;O4E^mi3;dp=P5TpxaY49@>; z%HbArFn#$u`cf`DHXw0H4cDN}rgfZ=lQCAnft_$4eh~N;{i1X<8B7-xJi`fMk$D9i zgiC^zK72KJJ>rOd9e9Iq>Hiusm>NIv7|#N!@t1ID6bD3VC2k7Z@irH<0zCEz<|Xei zpMyY)h?}kndX72dj(Z~v(aKN+o}~CH@HEBO5;p~^0pErU{f^|s!X@!Q=5Dux7zV*% zmrAfdag(5MBiEoBHM;?N;S$I7;WvYCvvH*T$?G06m@c??y>}sc84lZ#SQ5Mg-lF(6 z@Lh`UMEoZa->%3ee@HAhQLAzoP23cySQRJ<`ZlGX3;lYGA-O@3PuvdbAGqb3u&#VU zobuD!{(^T!t!XXb1k#P7M4l&9h=x9#R482^M9YNgGY!38Ym>sVYH(e|o;hi_ZU2S*^ zfs*UEW*z9`v2h$oxCENu!w&$pi1FvJ=GyhJ4!Fko&q$%JLieEt7)HtG^^}8_K ztDvt^`scxeUh5s7^1n$2(`W5!vuQ(u1UR&yC1y|MmJlvAJJW}s1zzS!OuwFBxVisd zqYT+_=umtKcnRyK%LT$A#Mt^4tiOVXG7oRDu;P+cudvc zW;mp7^48!U@CwDt!P^yo9Px_~-<1Vq8yQSfI}My5QRaO-*G#zd{RAI=7=B}W$cH~d+*B+EC#6O>d~fx1{uhG;`Wb;V z{}sFzfkgi=aZ|HMRnQ63x#i@DCi=sB^WO9C2pHt-CJsmY@M+*VxYQE;NyJTovQ&W< zL0{8LZ}Z;>hj``i7#tdVIhZ8RL7$@ZJD`_qKPk|+KK%RXbpAJeQ~WLuI{6x*=wrF* zgiD~wK0Fq@193z@)rZG}C%uOcM2f@7Fyy`Gon~i&hiviki@>84&jv40d z=$k+IuM!Rw%HbLCX2o9v?^66d@Z|Ts1#Jc|P~80vhI(cA9lS&F|G*PJ@Foa3j=QW} z@zLN>AA0o@h*L|rP63)iHjlY*NK+0MvV*fs>F+< z@SJg+4(Oj(yXBbUxrJhsK8Cm{(2DN(=>K_ekXt5_Al-*wMBFS~`M+=%B*I}O^pPKX zyQTs>L-7qR4CTu33V8FU-az%jmHq?E>5+}PpV$n2o6>&;?sh1{&oIPo^CsRy+%(;T zXgWFhM4iA*ovrjof#)fH40r+ap80n&8BBtb?!MtR&4EL;3bYjZRnW^l)5oE&Q~IaC z8$6uy*CEh-D)A3+i2KCb5`TgxDgF=m9L0lAEYb}|H9DK zW3Zh+D3NO%`kA*24ggP6d^~Y8hE}SUOM$*n=`T!lIYFl~WWymA_j)nCog2V26)&