diff --git a/.github/actions/brownie_fork_tests/action.yml b/.github/actions/brownie_fork_tests/action.yml index df85fc9b8..154eb024e 100644 --- a/.github/actions/brownie_fork_tests/action.yml +++ b/.github/actions/brownie_fork_tests/action.yml @@ -6,8 +6,8 @@ inputs: description: "vote type: normal or large" required: false default: "normal" - infura: - description: "infura JSON-RPC provider" + rpc_url: + description: "Ethereum RPC URL (any provider: Infura, Alchemy, custom)" required: true default: "" etherscan: @@ -74,6 +74,5 @@ runs: run: > ${{ inputs.command }} env: - WEB3_INFURA_PROJECT_ID: ${{ inputs.infura }} ETHERSCAN_TOKEN: ${{ inputs.etherscan }} - ETH_RPC_URL: "https://mainnet.infura.io/v3/${{ inputs.infura }}" + ETH_RPC_URL: ${{ inputs.rpc_url }} diff --git a/.github/workflows/core_tests.yml b/.github/workflows/core_tests.yml index 89dfa87fc..d99d0b7d0 100644 --- a/.github/workflows/core_tests.yml +++ b/.github/workflows/core_tests.yml @@ -36,12 +36,12 @@ jobs: - name: Run init script run: docker exec -e CORE_BRANCH tests-runner bash -c 'make init' env: - CORE_BRANCH: master + CORE_BRANCH: develop - name: Run node run: docker exec -e ETH_RPC_URL --detach tests-runner bash -c 'NODE_PORT=8546 make node' env: - ETH_RPC_URL: "https://mainnet.infura.io/v3/${{ secrets.WEB3_INFURA_PROJECT_ID }}" + ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }} - name: Check that the fork is ready shell: bash diff --git a/.github/workflows/dual_governance_regression.yml b/.github/workflows/dual_governance_regression.yml index 95aa5368a..0e2bf8aff 100644 --- a/.github/workflows/dual_governance_regression.yml +++ b/.github/workflows/dual_governance_regression.yml @@ -131,7 +131,7 @@ jobs: - name: Start Hardhat node shell: bash run: | - npx hardhat node --fork https://mainnet.infura.io/v3/${{ secrets.WEB3_INFURA_PROJECT_ID }} & + npx hardhat node --fork ${{ secrets.ETH_RPC_URL }} & for i in {1..30}; do if curl -sf ${{ env.HARDHAT_NODE_URL }} ${{ env.CURL_PARAMS }} | grep -q '"result"'; then echo "Hardhat node is ready" diff --git a/.github/workflows/large_vote_ci.yml b/.github/workflows/large_vote_ci.yml index 2f539b93f..004819bf2 100644 --- a/.github/workflows/large_vote_ci.yml +++ b/.github/workflows/large_vote_ci.yml @@ -34,7 +34,7 @@ jobs: uses: ./.github/actions/brownie_fork_tests with: vote: "large" - infura: ${{ secrets.WEB3_INFURA_PROJECT_ID }} + rpc_url: ${{ secrets.ETH_RPC_URL }} etherscan: ${{ secrets.ETHERSCAN_TOKEN }} command: "make test-1/2" @@ -60,6 +60,6 @@ jobs: uses: ./.github/actions/brownie_fork_tests with: vote: "large" - infura: ${{ secrets.WEB3_INFURA_PROJECT_ID }} + rpc_url: ${{ secrets.ETH_RPC_URL }} etherscan: ${{ secrets.ETHERSCAN_TOKEN }} command: "make test-2/2" diff --git a/.github/workflows/normal_vote_ci.yml b/.github/workflows/normal_vote_ci.yml index b9eb5457b..650d57bb7 100644 --- a/.github/workflows/normal_vote_ci.yml +++ b/.github/workflows/normal_vote_ci.yml @@ -21,7 +21,7 @@ jobs: uses: ./.github/actions/brownie_fork_tests with: vote: "normal" - infura: ${{ secrets.WEB3_INFURA_PROJECT_ID }} + rpc_url: ${{ secrets.ETH_RPC_URL }} etherscan: ${{ secrets.ETHERSCAN_TOKEN }} command: "make test-1/2" @@ -36,6 +36,6 @@ jobs: uses: ./.github/actions/brownie_fork_tests with: vote: "normal" - infura: ${{ secrets.WEB3_INFURA_PROJECT_ID }} + rpc_url: ${{ secrets.ETH_RPC_URL }} etherscan: ${{ secrets.ETHERSCAN_TOKEN }} command: "make test-2/2" diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 000000000..3186f3f07 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/Makefile b/Makefile index ac8e76243..a8070ac62 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ endif # Must be different from 8545 because core tests by default run its own fork on 8545 CORE_TESTS_TARGET_RPC_URL ?= http://127.0.0.1:8547 CORE_DIR ?= lido-core -CORE_BRANCH ?= master +CORE_BRANCH ?= develop NODE_PORT ?= 8545 SECONDARY_NETWORK ?= mfh-2 @@ -80,6 +80,7 @@ node3: test-core: cd $(CORE_DIR) && \ FORK_RPC_URL=$(CORE_TESTS_TARGET_RPC_URL) \ + RPC_URL=$(CORE_TESTS_TARGET_RPC_URL) \ yarn test:integration slots: diff --git a/archive/scripts/upgrade_tw_csm2.py b/archive/scripts/upgrade_tw_csm2.py new file mode 100644 index 000000000..da3b55b83 --- /dev/null +++ b/archive/scripts/upgrade_tw_csm2.py @@ -0,0 +1,910 @@ +""" +Upgrade to CSM v2, enable Triggerable Withdrawals, update the reward address and name for Node Operator ID 25 `Nethermind`, rotate Kiln Deposit Security Committee address + +Vote passed & executed on Sep-28-2025 03:34:35 PM UTC, block 23462419 +""" + +import time + +from typing import Any, Dict +from typing import Tuple +from brownie import interface, web3, convert + +from utils.agent import agent_forward +from utils.dsm import encode_remove_guardian, encode_add_guardian +from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description +from utils.permissions import encode_oz_grant_role, encode_oz_revoke_role +from utils.easy_track import ( + add_evmscript_factory, + create_permissions, +) +from utils.voting import bake_vote_items, confirm_vote_script, create_vote +from utils.dual_governance import submit_proposals +from utils.mainnet_fork import pass_and_exec_dao_vote +from utils.config import get_deployer_account, get_priority_fee, get_is_live +from utils.node_operators import encode_set_node_operator_name, encode_set_node_operator_reward_address + +# ============================= Constants =================================== +AGENT = "0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c" +ARAGON_KERNEL = "0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc" +NODE_OPERATORS_REGISTRY_ARAGON_APP_ID = "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d" +SIMPLE_DVT_ARAGON_APP_ID = "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4" + +CSM_COMMITTEE_MS = "0xC52fC3081123073078698F1EAc2f1Dc7Bd71880f" +CS_MODULE_ID = 3 +CS_MODULE_MODULE_FEE_BP = 600 +CS_MODULE_MAX_DEPOSITS_PER_BLOCK = 30 +CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE = 25 +CS_MODULE_TREASURY_FEE_BP = 400 +CS_GATE_SEAL_ADDRESS = "0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0" + +UTC13 = 60 * 60 * 13 +UTC19 = 60 * 60 * 19 + +# ============================== Addresses =================================== + +LIDO_LOCATOR = "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb" +VALIDATORS_EXIT_BUS_ORACLE = "0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e" +DUAL_GOVERNANCE = "0xC1db28B3301331277e307FDCfF8DE28242A4486E" +WITHDRAWAL_VAULT = "0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f" +ACCOUNTING_ORACLE = "0x852deD011285fe67063a08005c71a85690503Cee" +STAKING_ROUTER = "0xFdDf38947aFB03C621C71b06C9C70bce73f12999" +ACL = "0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb" +NODE_OPERATORS_REGISTRY = "0x55032650b14df07b85bF18A3a3eC8E0Af2e028d5" +SIMPLE_DVT = "0xaE7B191A31f627b4eB1d4DaC64eaB9976995b433" +ORACLE_DAEMON_CONFIG = "0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09" +CSM_ADDRESS = "0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F" +DEPOSIT_SECURITY_MODULE = "0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD" +WITHDRAWAL_QUEUE = "0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1" +CS_ACCOUNTING_ADDRESS = "0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da" +CS_FEE_ORACLE_ADDRESS = "0x4D4074628678Bd302921c20573EEa1ed38DdF7FB" +CS_FEE_DISTRIBUTOR_ADDRESS = "0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0" + +# New core contracts implementations +NEW_LIDO_LOCATOR_IMPL = "0x2C298963FB763f74765829722a1ebe0784f4F5Cf" +ACCOUNTING_ORACLE_IMPL = "0xE9906E543274cebcd335d2C560094089e9547e8d" +VALIDATORS_EXIT_BUS_ORACLE_IMPL = "0x905A211eD6830Cfc95643f0bE2ff64E7f3bf9b94" +WITHDRAWAL_VAULT_IMPL = "0x7D2BAa6094E1C4B60Da4cbAF4A77C3f4694fD53D" +STAKING_ROUTER_IMPL = "0x226f9265CBC37231882b7409658C18bB7738173A" +NODE_OPERATORS_REGISTRY_IMPL = "0x6828b023e737f96B168aCd0b5c6351971a4F81aE" + +TRIGGERABLE_WITHDRAWALS_GATEWAY = "0xDC00116a0D3E064427dA2600449cfD2566B3037B" +VALIDATOR_EXIT_VERIFIER = "0xbDb567672c867DB533119C2dcD4FB9d8b44EC82f" + +# Oracle consensus versions +AO_CONSENSUS_VERSION = 4 +VEBO_CONSENSUS_VERSION = 4 +CSM_CONSENSUS_VERSION = 3 + +# Fixed constants +EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS = 14 * 7200 # 14 days in slots (assuming 12 seconds per slot) +NOR_EXIT_DEADLINE_IN_SEC = 345600 # 28800 slots + +# VEB parameters +MAX_VALIDATORS_PER_REPORT = 600 +MAX_EXIT_REQUESTS_LIMIT = 11200 +EXITS_PER_FRAME = 1 +FRAME_DURATION_IN_SEC = 48 + +# CSM +CS_MODULE_NEW_TARGET_SHARE_BP = 500 # 5% +CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP = 625 # 6.25% + +CS_ACCOUNTING_IMPL_V2_ADDRESS = "0x6f09d2426c7405C5546413e6059F884D2D03f449" +CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS = "0x5DCF7cF7c6645E9E822a379dF046a8b0390251A1" +CS_FEE_ORACLE_IMPL_V2_ADDRESS = "0xe0B234f99E413E27D9Bc31aBba9A49A3e570Da97" +CSM_IMPL_V2_ADDRESS = "0x1eB6d4da13ca9566c17F526aE0715325d7a07665" + +CS_GATE_SEAL_V2_ADDRESS = "0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3" +CS_EJECTOR_ADDRESS = "0xc72b58aa02E0e98cF8A4a0E9Dce75e763800802C" +CS_PERMISSIONLESS_GATE_ADDRESS = "0xcF33a38111d0B1246A3F38a838fb41D626B454f0" +CS_VETTED_GATE_ADDRESS = "0xB314D4A76C457c93150d308787939063F4Cc67E0" +CS_VERIFIER_V2_ADDRESS = "0xdC5FE1782B6943f318E05230d688713a560063DC" + +CS_VERIFIER_ADDRESS_OLD = "0xeC6Cc185f671F627fb9b6f06C8772755F587b05d" +CS_CURVES = [ + ([1, 2.4 * 10**18], [2, 1.3 * 10**18]), # Default Curve + ([1, 1.5 * 10**18], [2, 1.3 * 10**18]), # Legacy EA Curve +] +CS_ICS_GATE_BOND_CURVE = ([1, 1.5 * 10**18], [2, 1.3 * 10**18]) # Identified Community Stakers Gate Bond Curve + +# GateSeals config +OLD_GATE_SEAL_ADDRESS = "0xf9C9fDB4A5D2AA1D836D5370AB9b28BC1847e178" +NEW_WQ_GATE_SEAL = "0x8A854C4E750CDf24f138f34A9061b2f556066912" +NEW_TW_GATE_SEAL = "0xA6BC802fAa064414AA62117B4a53D27fFfF741F1" +RESEAL_MANAGER = "0x7914b5a1539b97Bd0bbd155757F25FD79A522d24" + +# Add EasyTrack constants +EASYTRACK_EVMSCRIPT_EXECUTOR = "0xFE5986E06210aC1eCC1aDCafc0cc7f8D63B3F977" +EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0x8aa34dAaF0fC263203A15Bcfa0Ed926D466e59F3" +EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0xB7668B5485d0f826B86a75b0115e088bB9ee03eE" +EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY = "0xBc5642bDD6F2a54b01A75605aAe9143525D97308" + +# Vote enactment timeframe +DUAL_GOVERNANCE_TIME_CONSTRAINTS = "0x2a30F5aC03187674553024296bed35Aa49749DDa" + +# NO changes +NETHERMIND_NO_ID = 25 +NETHERMIND_NEW_REWARD_ADDRESS = "0x36201ed66DbC284132046ee8d99272F8eEeb24c8" +NETHERMIND_NEW_NO_NAME = "Twinstake" + +# DSM council rotation +OLD_KILN_ADDRESS = "0x14D5d5B71E048d2D75a39FfC5B407e3a3AB6F314" +NEW_KILN_ADDRESS = "0x6d22aE126eB2c37F67a1391B37FF4f2863e61389" +DSM_QUORUM_SIZE = 4 + +# ============================= Description ================================== +IPFS_DESCRIPTION = """ +1. **Upgrade to CSM v2 and increase CSM stake share limit from 3% to 5%**, as per [Snapshot decision](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0xc3f92bcdf8926cfa7528ca6a979c0fdce1e4d0cfaaa72dd6410a76a2e1e55766). Items 1.34-1.59. Audit & deployment verification by: [Statemind](https://github.com/lidofinance/audits/blob/main/Statemind%20Triggerable%20Withdrawals%20and%20CSM%20v2%20Audit%20Report%2009-2025.pdf) | [Ackee](https://github.com/lidofinance/audits/blob/main/Ackee%20Blockchain%20Community%20Staking%20Module%20v2%20Audit%20Report%2009-2025.pdf). +2. **Activate Triggerable Withdrawals**, as per [Snapshot decision](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x7d7f0e1a6d181310f8752af37e20515a9be258f30b211872f9acca99bc478851). Items 1.1-1.33, 1.60-1.66, 2-4. Audit & deployment verification by [Statemind](https://github.com/lidofinance/audits/blob/main/Statemind%20Triggerable%20Withdrawals%20and%20CSM%20v2%20Audit%20Report%2009-2025.pdf) | Audit by [Ackee](https://github.com/lidofinance/audits/blob/main/Ackee%20Blockchain%20Lido%20Triggerable%20Withdrawals%20Audit%20Report%2009-25.pdf). +3. **Update the reward address and name for Node Operator ID 25 `Nethermind`**, as per [Snapshot decision](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x3f68e9bc69850da419211c3d9f0a76d006ed044abc0f8bc845bc1d1cf3db0a8d). Items 1.67, 1.68. +4. **Rotate Deposit Security Committee address for `Kiln`**. [Requested on the forum](https://research.lido.fi/t/security-disclosure-kiln-precautionary-out-of-order-exits-in-response-security-incident/10654/3). Items 1.69, 1.70.""" + + +def encode_staking_router_proxy_update(implementation: str) -> Tuple[str, str]: + staking_router = interface.StakingRouter(STAKING_ROUTER) + proxy = interface.OssifiableProxy(staking_router) + return proxy.address, proxy.proxy__upgradeTo.encode_input(implementation) + + +def encode_proxy_upgrade_to(proxy: Any, implementation: str) -> Tuple[str, str]: + proxy = interface.OssifiableProxy(proxy) + return proxy.address, proxy.proxy__upgradeTo.encode_input(implementation) + + +def encode_wv_proxy_upgrade_to(proxy: Any, implementation: str) -> Tuple[str, str]: + proxy = interface.WithdrawalContractProxy(proxy) + + return proxy.address, proxy.proxy_upgradeTo.encode_input(implementation, b"") + + +def encode_oracle_upgrade_consensus(proxy: Any, consensus_version: int) -> Tuple[str, str]: + oracle = interface.BaseOracle(proxy) + return oracle.address, oracle.setConsensusVersion.encode_input(consensus_version) + + +def encode_staking_router_update_csm_module_share() -> Tuple[str, str]: + """Encode call to update CSM share limit""" + staking_router = interface.StakingRouter(STAKING_ROUTER) + return ( + staking_router.address, + staking_router.updateStakingModule.encode_input( + CS_MODULE_ID, + CS_MODULE_NEW_TARGET_SHARE_BP, + CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP, + CS_MODULE_MODULE_FEE_BP, + CS_MODULE_TREASURY_FEE_BP, + CS_MODULE_MAX_DEPOSITS_PER_BLOCK, + CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE, + ), + ) + + +def get_vote_items(): + lido_locator = interface.LidoLocator(LIDO_LOCATOR) + validator_exit_bus_oracle = interface.ValidatorsExitBusOracle(VALIDATORS_EXIT_BUS_ORACLE) + agent = interface.Agent(AGENT) + dual_governance = interface.DualGovernance(DUAL_GOVERNANCE) + withdrawal_vault = interface.WithdrawalVault(WITHDRAWAL_VAULT) + accounting_oracle = interface.AccountingOracle(ACCOUNTING_ORACLE) + staking_router = interface.StakingRouter(STAKING_ROUTER) + acl = interface.ACL(ACL) + kernel = interface.Kernel(ARAGON_KERNEL) + nor = interface.NodeOperatorsRegistry(NODE_OPERATORS_REGISTRY) + simple_dvt = interface.SimpleDVT(SIMPLE_DVT) + oracle_daemon_config = interface.OracleDaemonConfig(ORACLE_DAEMON_CONFIG) + csm = interface.CSModule(CSM_ADDRESS) + dsm = interface.DepositSecurityModule(DEPOSIT_SECURITY_MODULE) + withdrawal_queue = interface.WithdrawalQueueERC721(WITHDRAWAL_QUEUE) + cs_accounting = interface.CSAccounting(CS_ACCOUNTING_ADDRESS) + cs_fee_oracle = interface.CSFeeOracle(CS_FEE_ORACLE_ADDRESS) + cs_fee_distributor = interface.CSFeeDistributor(CS_FEE_DISTRIBUTOR_ADDRESS) + triggerable_withdrawal_gateway = interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY) + + dg_items = [ + # --- locator + # "1.1. Update Lido Locator `0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb` implementation to `0x2C298963FB763f74765829722a1ebe0784f4F5Cf`", + agent_forward([encode_proxy_upgrade_to(lido_locator, NEW_LIDO_LOCATOR_IMPL)]), + # --- VEB + # "1.2. Update Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` implementation to `0x905A211eD6830Cfc95643f0bE2ff64E7f3bf9b94`", + agent_forward([encode_proxy_upgrade_to(validator_exit_bus_oracle, VALIDATORS_EXIT_BUS_ORACLE_IMPL)]), + # "1.3. Call `finalizeUpgrade_v2(maxValidatorsPerReport = 600, maxExitRequestsLimit = 11200, exitsPerFrame = 1, frameDurationInSec = 48)` on Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e`", + agent_forward( + [ + ( + VALIDATORS_EXIT_BUS_ORACLE, + validator_exit_bus_oracle.finalizeUpgrade_v2.encode_input( + MAX_VALIDATORS_PER_REPORT, MAX_EXIT_REQUESTS_LIMIT, EXITS_PER_FRAME, FRAME_DURATION_IN_SEC + ), + ) + ] + ), + # "1.4. Grant Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` role `MANAGE_CONSENSUS_VERSION_ROLE` to Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_grant_role( + contract=validator_exit_bus_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + grant_to=AGENT, + ) + ] + ), + # "1.5. Bump Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` consensus version to `4`", + agent_forward([encode_oracle_upgrade_consensus(validator_exit_bus_oracle, VEBO_CONSENSUS_VERSION)]), + # "1.6. Revoke Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` role `MANAGE_CONSENSUS_VERSION_ROLE` from Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_revoke_role( + contract=validator_exit_bus_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + revoke_from=AGENT, + ) + ] + ), + # "1.7. Grant Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` role `SUBMIT_REPORT_HASH_ROLE` to EasyTrack EVM Script Executor `0xFE5986E06210aC1eCC1aDCafc0cc7f8D63B3F977`", + agent_forward( + [ + encode_oz_grant_role( + contract=validator_exit_bus_oracle, + role_name="SUBMIT_REPORT_HASH_ROLE", + grant_to=EASYTRACK_EVMSCRIPT_EXECUTOR, + ) + ] + ), + # --- Triggerable Withdrawals Gateway (TWG) + # "1.8. Grant Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` role `ADD_FULL_WITHDRAWAL_REQUEST_ROLE` to CS Ejector `0xc72b58aa02E0e98cF8A4a0E9Dce75e763800802C`", + agent_forward( + [ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="ADD_FULL_WITHDRAWAL_REQUEST_ROLE", + grant_to=CS_EJECTOR_ADDRESS, + ) + ] + ), + # "1.9. Grant Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` role `ADD_FULL_WITHDRAWAL_REQUEST_ROLE` to Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e`", + agent_forward( + [ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="ADD_FULL_WITHDRAWAL_REQUEST_ROLE", + grant_to=VALIDATORS_EXIT_BUS_ORACLE, + ) + ] + ), + # "1.10. Add Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` as a sealable withdrawals blocker to Dual Governance `0xC1db28B3301331277e307FDCfF8DE28242A4486E`", + ( + DUAL_GOVERNANCE, + dual_governance.addTiebreakerSealableWithdrawalBlocker.encode_input( + TRIGGERABLE_WITHDRAWALS_GATEWAY + ), + ), + # --- WV + # "1.11. Update Withdrawal Vault `0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f` implementation to `0x7D2BAa6094E1C4B60Da4cbAF4A77C3f4694fD53D`", + agent_forward([encode_wv_proxy_upgrade_to(withdrawal_vault, WITHDRAWAL_VAULT_IMPL)]), + # "1.12. Call `finalizeUpgrade_v2()` on Withdrawal Vault `0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f`", + agent_forward( + [ + ( + WITHDRAWAL_VAULT, + withdrawal_vault.finalizeUpgrade_v2.encode_input(), + ) + ] + ), + # --- AO + # "1.13. Update Accounting Oracle `0x852deD011285fe67063a08005c71a85690503Cee` implementation to `0xE9906E543274cebcd335d2C560094089e9547e8d`", + agent_forward([encode_proxy_upgrade_to(accounting_oracle, ACCOUNTING_ORACLE_IMPL)]), + # "1.14. Grant Accounting Oracle `0x852deD011285fe67063a08005c71a85690503Cee` role `MANAGE_CONSENSUS_VERSION_ROLE` to Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_grant_role( + contract=accounting_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + grant_to=AGENT, + ) + ] + ), + # "1.15. Bump Accounting Oracle `0x852deD011285fe67063a08005c71a85690503Cee` consensus version to `4`", + agent_forward([encode_oracle_upgrade_consensus(accounting_oracle, AO_CONSENSUS_VERSION)]), + # "1.16. Revoke Accounting Oracle `0x852deD011285fe67063a08005c71a85690503Cee` role `MANAGE_CONSENSUS_VERSION_ROLE` from Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_revoke_role( + contract=accounting_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + revoke_from=AGENT, + ) + ] + ), + # "1.17. Call `finalizeUpgrade_v3()` on Accounting Oracle `0x852deD011285fe67063a08005c71a85690503Cee`", + agent_forward( + [ + ( + ACCOUNTING_ORACLE, + accounting_oracle.finalizeUpgrade_v3.encode_input(), + ) + ] + ), + # --- SR + # "1.18. Update Staking Router `0xFdDf38947aFB03C621C71b06C9C70bce73f12999` implementation to `0x226f9265CBC37231882b7409658C18bB7738173A`", + agent_forward([encode_staking_router_proxy_update(STAKING_ROUTER_IMPL)]), + # "1.19. Call `finalizeUpgrade_v3()` on Staking Router `0xFdDf38947aFB03C621C71b06C9C70bce73f12999`", + agent_forward( + [ + ( + STAKING_ROUTER, + staking_router.finalizeUpgrade_v3.encode_input(), + ) + ] + ), + # "1.20. Grant Staking Router `0xFdDf38947aFB03C621C71b06C9C70bce73f12999` role `REPORT_VALIDATOR_EXITING_STATUS_ROLE` to Validator Exit Delay Verifier `0xbDb567672c867DB533119C2dcD4FB9d8b44EC82f`", + agent_forward( + [ + encode_oz_grant_role( + contract=staking_router, + role_name="REPORT_VALIDATOR_EXITING_STATUS_ROLE", + grant_to=VALIDATOR_EXIT_VERIFIER, + ) + ] + ), + # "1.21. Grant Staking Router `0xFdDf38947aFB03C621C71b06C9C70bce73f12999` role `REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE` to Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B`", + agent_forward( + [ + encode_oz_grant_role( + contract=staking_router, + role_name="REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE", + grant_to=TRIGGERABLE_WITHDRAWALS_GATEWAY, + ) + ] + ), + # --- Curated Staking Module and sDVT + # "1.22. Grant `APP_MANAGER_ROLE` role to Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c` on Lido DAO Kernel `0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc` via Aragon ACL `0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb`", + agent_forward( + [ + ( + acl.address, + acl.grantPermission.encode_input( + AGENT, + ARAGON_KERNEL, + convert.to_uint(web3.keccak(text="APP_MANAGER_ROLE")), + ), + ) + ] + ), + # "1.23. Update Curated Module (Aragon APP ID = `0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d`) implementation to `0x6828b023e737f96B168aCd0b5c6351971a4F81aE` via Lido DAO Kernel `0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc`", + agent_forward( + [ + ( + kernel.address, + kernel.setApp.encode_input( + kernel.APP_BASES_NAMESPACE(), + NODE_OPERATORS_REGISTRY_ARAGON_APP_ID, + NODE_OPERATORS_REGISTRY_IMPL, + ), + ) + ] + ), + # "1.24. Call `finalizeUpgrade_v4(norExitDeadlineInSec = 345600)` on Curated Staking Module Node Operators Registry `0x55032650b14df07b85bF18A3a3eC8E0Af2e028d5`", + agent_forward( + [ + ( + interface.NodeOperatorsRegistry(nor).address, + interface.NodeOperatorsRegistry(nor).finalizeUpgrade_v4.encode_input( + NOR_EXIT_DEADLINE_IN_SEC + ), + ) + ] + ), + # "1.25. Update Simple DVT (Aragon APP ID = `0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4`) implementation to `0x6828b023e737f96B168aCd0b5c6351971a4F81aE` via Lido DAO Kernel `0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc`", + agent_forward( + [ + ( + kernel.address, + kernel.setApp.encode_input( + kernel.APP_BASES_NAMESPACE(), + SIMPLE_DVT_ARAGON_APP_ID, + NODE_OPERATORS_REGISTRY_IMPL, + ), + ) + ] + ), + # "1.26. Call `finalizeUpgrade_v4(norExitDeadlineInSec = 345600)` on Simple DVT Staking Module Node Operators Registry `0xaE7B191A31f627b4eB1d4DaC64eaB9976995b433`", + agent_forward( + [ + ( + interface.NodeOperatorsRegistry(simple_dvt).address, + interface.NodeOperatorsRegistry(simple_dvt).finalizeUpgrade_v4.encode_input( + NOR_EXIT_DEADLINE_IN_SEC + ), + ) + ] + ), + # "1.27. Revoke `APP_MANAGER_ROLE` role from Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c` on Lido DAO Kernel `0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc` via Aragon ACL `0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb`", + agent_forward( + [ + ( + acl.address, + acl.revokePermission.encode_input( + AGENT, + ARAGON_KERNEL, + convert.to_uint(web3.keccak(text="APP_MANAGER_ROLE")), + ), + ) + ] + ), + # --- Oracle configs + # "1.28. Grant Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09` role `CONFIG_MANAGER_ROLE` to Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_grant_role( + contract=oracle_daemon_config, + role_name="CONFIG_MANAGER_ROLE", + grant_to=AGENT, + ) + ] + ), + # "1.29. Remove `NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP` variable from Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09`", + agent_forward( + [ + ( + oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input("NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP"), + ) + ] + ), + # "1.30. Remove `VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS` variable from Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09`", + agent_forward( + [ + ( + oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input("VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS"), + ) + ] + ), + # "1.31. Remove `VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS` variable from Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09`", + agent_forward( + [ + ( + oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input("VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS"), + ) + ] + ), + # "1.32. Add `EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS=14 * 7200` variable to Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09`", + agent_forward( + [ + ( + oracle_daemon_config.address, + oracle_daemon_config.set.encode_input( + "EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS", EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS + ), + ) + ] + ), + # "1.33. Revoke Oracle Daemon Config `0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09` role `CONFIG_MANAGER_ROLE` from Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_revoke_role( + contract=oracle_daemon_config, + role_name="CONFIG_MANAGER_ROLE", + revoke_from=AGENT, + ) + ] + ), + # --- CSM + # "1.34. Update CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` implementation to `0x1eB6d4da13ca9566c17F526aE0715325d7a07665`", + agent_forward( + [ + encode_proxy_upgrade_to(csm, CSM_IMPL_V2_ADDRESS) + ] + ), + # "1.35. Call `finalizeUpgradeV2()` on CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F`", + agent_forward( + [ + ( + csm.address, + csm.finalizeUpgradeV2.encode_input(), + ) + ] + ), + # "1.36. Update CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` implementation to `0x6f09d2426c7405C5546413e6059F884D2D03f449`", + agent_forward( + [ + encode_proxy_upgrade_to( + cs_accounting, + CS_ACCOUNTING_IMPL_V2_ADDRESS, + ) + ] + ), + # "1.37. Call `finalizeUpgradeV2(bondCurves=[ ([1, 2.4 * 10**18], [2, 1.3 * 10**18]), ([1, 1.5 * 10**18], [2, 1.3 * 10**18]) ])` on CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da`", + agent_forward( + [ + ( + cs_accounting.address, + cs_accounting.finalizeUpgradeV2.encode_input(CS_CURVES), + ) + ] + ), + # "1.38. Update CSFeeOracle `0x4D4074628678Bd302921c20573EEa1ed38DdF7FB` implementation to `0xe0B234f99E413E27D9Bc31aBba9A49A3e570Da97`", + agent_forward( + [ + encode_proxy_upgrade_to( + cs_fee_oracle, + CS_FEE_ORACLE_IMPL_V2_ADDRESS, + ) + ] + ), + # "1.39. Call `finalizeUpgradeV2(consensusVersion=3)` on CSFeeOracle `0x4D4074628678Bd302921c20573EEa1ed38DdF7FB`", + agent_forward( + [ + ( + cs_fee_oracle.address, + cs_fee_oracle.finalizeUpgradeV2.encode_input(CSM_CONSENSUS_VERSION), + ) + ] + ), + # "1.40. Update CSFeeDistributor `0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0` implementation to `0x5DCF7cF7c6645E9E822a379dF046a8b0390251A1`", + agent_forward( + [ + encode_proxy_upgrade_to( + cs_fee_distributor, + CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS, + ) + ] + ), + # "1.41. Call `finalizeUpgradeV2(_rebateRecipient=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c)` on CSFeeDistributor `0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0`", + agent_forward( + [ + ( + cs_fee_distributor.address, + cs_fee_distributor.finalizeUpgradeV2.encode_input(agent), + ) + ] + ), + # "1.42. Revoke CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `SET_BOND_CURVE_ROLE` from CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="SET_BOND_CURVE_ROLE", + revoke_from=csm, + ) + ] + ), + # "1.43. Revoke CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `RESET_BOND_CURVE_ROLE` from CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="RESET_BOND_CURVE_ROLE", + revoke_from=csm, + ) + ] + ), + # "1.44. Revoke CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `RESET_BOND_CURVE_ROLE` from CSM Committee `0xC52fC3081123073078698F1EAc2f1Dc7Bd71880f`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="RESET_BOND_CURVE_ROLE", + revoke_from=CSM_COMMITTEE_MS, + ) + ] + ), + # "1.45. Grant CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `CREATE_NODE_OPERATOR_ROLE` for CS Permissionless Gate `0xcF33a38111d0B1246A3F38a838fb41D626B454f0`", + agent_forward( + [ + encode_oz_grant_role( + contract=csm, + role_name="CREATE_NODE_OPERATOR_ROLE", + grant_to=CS_PERMISSIONLESS_GATE_ADDRESS, + ) + ] + ), + # "1.46. Grant CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `CREATE_NODE_OPERATOR_ROLE` for CS Vetted Gate `0xB314D4A76C457c93150d308787939063F4Cc67E0`", + agent_forward( + [ + encode_oz_grant_role( + contract=csm, + role_name="CREATE_NODE_OPERATOR_ROLE", + grant_to=CS_VETTED_GATE_ADDRESS, + ) + ] + ), + # "1.47. Grant CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `SET_BOND_CURVE_ROLE` for CS Vetted Gate `0xB314D4A76C457c93150d308787939063F4Cc67E0`", + agent_forward( + [ + encode_oz_grant_role( + contract=cs_accounting, + role_name="SET_BOND_CURVE_ROLE", + grant_to=CS_VETTED_GATE_ADDRESS, + ) + ] + ), + # "1.48. Revoke CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `VERIFIER_ROLE` from the previous instance of CS Verifier `0xeC6Cc185f671F627fb9b6f06C8772755F587b05d`", + agent_forward( + [ + encode_oz_revoke_role( + contract=csm, + role_name="VERIFIER_ROLE", + revoke_from=CS_VERIFIER_ADDRESS_OLD, + ) + ] + ), + # "1.49. Grant CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `VERIFIER_ROLE` to the new instance of CS Verifier `0xdC5FE1782B6943f318E05230d688713a560063DC`", + agent_forward( + [ + encode_oz_grant_role( + contract=csm, + role_name="VERIFIER_ROLE", + grant_to=CS_VERIFIER_V2_ADDRESS, + ) + ] + ), + # "1.50. Revoke CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `PAUSE_ROLE` from the previous GateSeal instance `0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0`", + agent_forward( + [ + encode_oz_revoke_role( + contract=csm, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS, + ) + ] + ), + # "1.51. Revoke CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `PAUSE_ROLE` from the previous GateSeal instance `0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS, + ) + ] + ), + # "1.52. Revoke CSFeeOracle `0x4D4074628678Bd302921c20573EEa1ed38DdF7FB` role `PAUSE_ROLE` from the previous GateSeal instance `0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_fee_oracle, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS, + ) + ] + ), + # "1.53. Grant CSM `0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F` role `PAUSE_ROLE` for the new GateSeal instance `0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3`", + agent_forward( + [ + encode_oz_grant_role( + contract=csm, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS, + ) + ] + ), + # "1.54. Grant CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `PAUSE_ROLE` for the new GateSeal instance `0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3`", + agent_forward( + [ + encode_oz_grant_role( + contract=cs_accounting, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS, + ) + ] + ), + # "1.55. Grant CSFeeOracle `0x4D4074628678Bd302921c20573EEa1ed38DdF7FB` role `PAUSE_ROLE` for the new GateSeal instance `0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3`", + agent_forward( + [ + encode_oz_grant_role( + contract=cs_fee_oracle, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS, + ) + ] + ), + # "1.56. Grant CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `MANAGE_BOND_CURVES_ROLE` to Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_grant_role( + contract=cs_accounting, + role_name="MANAGE_BOND_CURVES_ROLE", + grant_to=agent, + ) + ] + ), + # "1.57. Add Identified Community Stakers Gate Bond Curve `([1, 1.5 * 10**18], [2, 1.3 * 10**18])` to CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da`", + agent_forward( + [ + ( + cs_accounting.address, + cs_accounting.addBondCurve.encode_input(CS_ICS_GATE_BOND_CURVE), + ) + ] + ), + # "1.58. Revoke CSAccounting `0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da` role `MANAGE_BOND_CURVES_ROLE` from Aragon Agent `0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c`", + agent_forward( + [ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="MANAGE_BOND_CURVES_ROLE", + revoke_from=agent, + ) + ] + ), + # "1.59. Increase CSM (`MODULE_ID = 3`) share limit from `3%` to `5%` and priority exit threshold from `3.75%` to `6.25%` in Staking Router `0xFdDf38947aFB03C621C71b06C9C70bce73f12999`", + agent_forward([encode_staking_router_update_csm_module_share()]), + # --- Gate Seals + # "1.60. Revoke Withdrawal Queue `0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1` role `PAUSE_ROLE` from the old GateSeal `0xf9C9fDB4A5D2AA1D836D5370AB9b28BC1847e178`", + agent_forward( + [ + encode_oz_revoke_role( + contract=withdrawal_queue, + role_name="PAUSE_ROLE", + revoke_from=OLD_GATE_SEAL_ADDRESS, + ) + ] + ), + # "1.61. Revoke Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` role `PAUSE_ROLE` from the old GateSeal `0xf9C9fDB4A5D2AA1D836D5370AB9b28BC1847e178`", + agent_forward( + [ + encode_oz_revoke_role( + contract=validator_exit_bus_oracle, + role_name="PAUSE_ROLE", + revoke_from=OLD_GATE_SEAL_ADDRESS, + ) + ] + ), + # "1.62. Grant Withdrawal Queue `0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1` role `PAUSE_ROLE` to the new Withdrawal Queue GateSeal `0x8A854C4E750CDf24f138f34A9061b2f556066912`", + agent_forward( + [ + encode_oz_grant_role( + contract=withdrawal_queue, + role_name="PAUSE_ROLE", + grant_to=NEW_WQ_GATE_SEAL, + ) + ] + ), + # "1.63. Grant Validators Exit Bus Oracle `0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e` role `PAUSE_ROLE` to the new Triggerable Withdrawals GateSeal `0xA6BC802fAa064414AA62117B4a53D27fFfF741F1`", + agent_forward( + [ + encode_oz_grant_role( + contract=validator_exit_bus_oracle, + role_name="PAUSE_ROLE", + grant_to=NEW_TW_GATE_SEAL, + ) + ] + ), + # "1.64. Grant Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` role `PAUSE_ROLE` to the new Triggerable Withdrawals GateSeal `0xA6BC802fAa064414AA62117B4a53D27fFfF741F1`", + agent_forward( + [ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="PAUSE_ROLE", + grant_to=NEW_TW_GATE_SEAL, + ) + ] + ), + # "1.65. Grant Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` role `PAUSE_ROLE` to Reseal Manager `0x7914b5a1539b97Bd0bbd155757F25FD79A522d24`", + agent_forward( + [ + encode_oz_grant_role( + contract=triggerable_withdrawal_gateway, + role_name="PAUSE_ROLE", + grant_to=RESEAL_MANAGER, + ) + ] + ), + # "1.66. Grant Triggerable Withdrawals Gateway `0xDC00116a0D3E064427dA2600449cfD2566B3037B` role `RESUME_ROLE` to Reseal Manager `0x7914b5a1539b97Bd0bbd155757F25FD79A522d24`", + agent_forward( + [ + encode_oz_grant_role( + contract=triggerable_withdrawal_gateway, + role_name="RESUME_ROLE", + grant_to=RESEAL_MANAGER, + ) + ] + ), + # "1.67. Rename Node Operator `ID 25` from `Nethermind` to `Twinstake`" + agent_forward( + [ + encode_set_node_operator_name(id=NETHERMIND_NO_ID, name=NETHERMIND_NEW_NO_NAME, registry=nor), + ] + ), + # "1.68. Change Node Operator `ID 25` reward address from `0x237DeE529A47750bEcdFa8A59a1D766e3e7B5F91` to `0x36201ed66DbC284132046ee8d99272F8eEeb24c8`" + agent_forward( + [ + encode_set_node_operator_reward_address(id=NETHERMIND_NO_ID, rewardAddress=NETHERMIND_NEW_REWARD_ADDRESS, registry=nor), + ] + ), + # "1.69. Remove old `Kiln` address `0x14D5d5B71E048d2D75a39FfC5B407e3a3AB6F314` from Deposit Security Module `0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD` and keep quorum size as `4`" + agent_forward( + [ + encode_remove_guardian(dsm=dsm, guardian_address=OLD_KILN_ADDRESS, quorum_size=DSM_QUORUM_SIZE), + ] + ), + # "1.70. Add new `Kiln` address `0x6d22aE126eB2c37F67a1391B37FF4f2863e61389` to Deposit Security Module `0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD` and keep quorum size as `4`" + agent_forward( + [ + encode_add_guardian(dsm=dsm, guardian_address=NEW_KILN_ADDRESS, quorum_size=DSM_QUORUM_SIZE), + ] + ), + # "1.71. Set time constraints for Dual Governance Proposal execution (13:00 to 19:00 UTC) on Dual Governance Time Constraints `0x2a30F5aC03187674553024296bed35Aa49749DDa`" + ( + DUAL_GOVERNANCE_TIME_CONSTRAINTS, + interface.TimeConstraints(DUAL_GOVERNANCE_TIME_CONSTRAINTS).checkTimeWithinDayTimeAndEmit.encode_input( + UTC13, # 13:00 UTC + UTC19, # 19:00 UTC + ), + ), + ] + dg_call_script = submit_proposals( + [ + ( + dg_items, + "Upgrade to CSM v2, enable Triggerable Withdrawals, update the reward address and name for Node Operator ID 25 `Nethermind`, rotate Kiln Deposit Security Committee address", + ) + ] + ) + + vote_desc_items, call_script_items = zip( + ( + "1. Submit a Dual Governance proposal to upgrade to CSM v2, enable Triggerable Withdrawals, update the reward address and name for Node Operator ID 25 `Nethermind`, rotate Kiln Deposit Security Committee address", + dg_call_script[0], + ), + ( + "2. Add CSSetVettedGateTree factory `0xBc5642bDD6F2a54b01A75605aAe9143525D97308` to EasyTrack `0xF0211b7660680B49De1A7E9f25C65660F0a13Fea` with permissions `setTreeParams`", + add_evmscript_factory( + factory=EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY, + permissions=(create_permissions(interface.CSVettedGate(CS_VETTED_GATE_ADDRESS), "setTreeParams")), + ), + ), + ( + "3. Add SubmitValidatorsExitRequestHashes (Simple DVT) EVM script factory `0xB7668B5485d0f826B86a75b0115e088bB9ee03eE` to Easy Track `0xF0211b7660680B49De1A7E9f25C65660F0a13Fea` with permissions `submitExitRequestsHash`", + add_evmscript_factory( + factory=EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY, + permissions=(create_permissions(validator_exit_bus_oracle, "submitExitRequestsHash")), + ), + ), + ( + "4. Add SubmitValidatorsExitRequestHashes (Curated Module) EVM script factory `0x8aa34dAaF0fC263203A15Bcfa0Ed926D466e59F3` to Easy Track `0xF0211b7660680B49De1A7E9f25C65660F0a13Fea` with permissions `submitExitRequestsHash`", + add_evmscript_factory( + factory=EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY, + permissions=(create_permissions(validator_exit_bus_oracle, "submitExitRequestsHash")), + ), + ), + ) + + return vote_desc_items, call_script_items + + +def start_vote(tx_params: Dict[str, str], silent: bool = False): + vote_desc_items, call_script_items = get_vote_items() + vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items)) + + desc_ipfs = ( + calculate_vote_ipfs_description(IPFS_DESCRIPTION) if silent else upload_vote_ipfs_description(IPFS_DESCRIPTION) + ) + + assert confirm_vote_script(vote_items, silent, desc_ipfs) + + return create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs) + + +def main(): + tx_params: Dict[str, str] = {"from": get_deployer_account().address} + if get_is_live(): + tx_params["priority_fee"] = get_priority_fee() + + vote_id, _ = start_vote(tx_params=tx_params, silent=False) + vote_id >= 0 and print(f"Vote created: {vote_id}.") + + time.sleep(5) # hack for waiting thread #2. + + +def start_and_execute_vote_on_fork_manual(): + if get_is_live(): + raise Exception("This script is for local testing only.") + + tx_params = {"from": get_deployer_account()} + vote_id, _ = start_vote(tx_params=tx_params, silent=True) + print(f"Vote created: {vote_id}.") + pass_and_exec_dao_vote(int(vote_id), step_by_step=True) diff --git a/archive/tests/shapella_upgrade_acceptance/test_accounting_oracle_negative.py b/archive/tests/shapella_upgrade_acceptance/test_accounting_oracle_negative.py index bd9107f3d..33f03bc27 100644 --- a/archive/tests/shapella_upgrade_acceptance/test_accounting_oracle_negative.py +++ b/archive/tests/shapella_upgrade_acceptance/test_accounting_oracle_negative.py @@ -822,6 +822,6 @@ def build_extra_data_item( module_id.to_bytes(FIELDS_WIDTH.MODULE_ID, **opts), len(nos_ids).to_bytes(FIELDS_WIDTH.NODE_OPS_COUNT, **opts), b"".join(i.to_bytes(FIELDS_WIDTH.NODE_OPERATOR_IDS, **opts) for i in nos_ids), - b"".join(i.to_bytes(FIELDS_WIDTH.STUCK_OR_EXITED_VALS_COUNT, **opts) for i in vals_count), + b"".join(i.to_bytes(FIELDS_WIDTH.EXITED_VALS_COUNT, **opts) for i in vals_count), ) ) diff --git a/archive/tests/test_tw_csm2.py b/archive/tests/test_tw_csm2.py new file mode 100644 index 000000000..76cf7ae56 --- /dev/null +++ b/archive/tests/test_tw_csm2.py @@ -0,0 +1,2041 @@ +from typing import Optional +from brownie.network.transaction import TransactionReceipt + +from utils.dsm import encode_remove_guardian, encode_add_guardian +from utils.test.tx_tracing_helpers import ( + count_vote_items_by_events, + display_dg_events, +) + +from brownie.exceptions import VirtualMachineError +from brownie import interface, reverts, chain, convert, web3, ZERO_ADDRESS # type: ignore +from brownie.network.event import EventDict +from utils.easy_track import create_permissions +from utils.evm_script import encode_call_script +from utils.voting import find_metadata_by_vote_id +from utils.ipfs import get_lido_vote_cid_from_str +from utils.dual_governance import PROPOSAL_STATUS, wait_for_time_window +from utils.test.event_validators.node_operators_registry import ( + validate_node_operator_name_set_event, + validate_node_operator_reward_address_set_event, + NodeOperatorNameSetItem, + NodeOperatorRewardAddressSetItem, +) +from utils.test.tx_tracing_helpers import group_voting_events_from_receipt, group_dg_events_from_receipt +from utils.test.event_validators.easy_track import validate_evmscript_factory_added_event, EVMScriptFactoryAdded +from utils.test.event_validators.dual_governance import validate_dual_governance_submit_event +from utils.test.event_validators.common import validate_events_chain + + +def validate_proxy_upgrade_event(event: EventDict, implementation: str, emitted_by: Optional[str] = None, events_chain: Optional[list] = None): + _events_chain = events_chain or ["LogScriptCall", "Upgraded", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("Upgraded") == 1 + + assert "Upgraded" in event, "No Upgraded event found" + + assert event["Upgraded"][0]["implementation"] == implementation, "Wrong implementation address" + + if emitted_by is not None: + assert convert.to_address(event["Upgraded"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_consensus_version_set_event(event: EventDict, new_version: int, prev_version: int, + emitted_by: Optional[str] = None, events_chain: Optional[list] = None): + _events_chain = events_chain or ["LogScriptCall", "ConsensusVersionSet", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("ConsensusVersionSet") == 1 + + assert "ConsensusVersionSet" in event, "No ConsensusVersionSet event found" + + assert event["ConsensusVersionSet"][0]["version"] == new_version, "Wrong new version" + + assert event["ConsensusVersionSet"][0]["prevVersion"] == prev_version, "Wrong previous version" + + if emitted_by is not None: + assert convert.to_address(event["ConsensusVersionSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_role_grant_event(event: EventDict, role_hash: str, account: str, emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "RoleGranted", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("RoleGranted") == 1 + + assert "RoleGranted" in event, "No RoleGranted event found" + + # Strip 0x prefix for consistent comparison + expected_role_hash = role_hash.replace('0x', '') + actual_role_hash = event["RoleGranted"][0]["role"].hex().replace('0x', '') + + assert actual_role_hash == expected_role_hash, "Wrong role hash" + + assert convert.to_address(event["RoleGranted"][0]["account"]) == convert.to_address(account), "Wrong account" + + if emitted_by is not None: + assert convert.to_address(event["RoleGranted"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_role_revoke_event(event: EventDict, role_hash: str, account: str, emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "RoleRevoked", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("RoleRevoked") == 1 + + assert "RoleRevoked" in event, "No RoleRevoked event found" + + # Strip 0x prefix for consistent comparison + expected_role_hash = role_hash.replace('0x', '') + actual_role_hash = event["RoleRevoked"][0]["role"].hex().replace('0x', '') + + assert actual_role_hash == expected_role_hash, "Wrong role hash" + + assert convert.to_address(event["RoleRevoked"][0]["account"]) == convert.to_address(account), "Wrong account" + + if emitted_by is not None: + assert convert.to_address(event["RoleRevoked"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_contract_version_set_event(event: EventDict, version: int, emitted_by: Optional[str] = None, events_chain: Optional[list] = None): + _events_chain = events_chain or ["LogScriptCall", "ContractVersionSet", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("ContractVersionSet") == 1 + + assert "ContractVersionSet" in event, "No ContractVersionSet event found" + + assert event["ContractVersionSet"][0]["version"] == version, "Wrong version" + + if emitted_by is not None: + assert convert.to_address(event["ContractVersionSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_bond_curve_added_event(event: EventDict, curve_id: int, curve_intervals: tuple[list[int], list[int]], emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "BondCurveAdded", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("BondCurveAdded") == 1 + + assert "BondCurveAdded" in event, "No BondCurveAdded event found" + + assert event["BondCurveAdded"][0]["curveId"] == curve_id, "Wrong curve ID" + assert event["BondCurveAdded"][0]["bondCurveIntervals"] == curve_intervals, "Wrong curve intervals" + + if emitted_by is not None: + assert convert.to_address(event["BondCurveAdded"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_bond_curve_added_on_init_v2_events(event: EventDict, curves_intervals: list[tuple[list[int], list[int]]], emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "BondCurveAdded", "BondCurveAdded", 'Initialized', "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("BondCurveAdded") == 2 + + assert "BondCurveAdded" in event, "No BondCurveAdded event found" + + for curve_id, curve_intervals in enumerate(curves_intervals): + found = False + for e in event["BondCurveAdded"]: + if e["curveId"] == curve_id and e["bondCurveIntervals"] == curve_intervals: + found = True + break + assert found, f"Curve with ID {curve_id} and intervals {curve_intervals} not found" + + if emitted_by is not None: + assert convert.to_address(event["BondCurveAdded"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_added_bond_curve(curve: list[tuple[int, int, int]], expected_curve: tuple[list[int], list[int]]): + assert len(curve) == len(expected_curve), "Bond curve should have correct number of intervals" + for i, interval in enumerate(curve): + keys, _, trend = interval + expected_keys, expected_trend = expected_curve[i] + assert keys == expected_keys, f"Curve interval {i} keys should be {expected_keys}" + assert trend == expected_trend, f"Curve interval {i} trend should be {expected_trend}" + + +def validate_remove_guardian_event(event: EventDict, guardian_address: str, emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "GuardianRemoved", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("GuardianRemoved") == 1 + + assert "GuardianRemoved" in event, "No GuardianRemoved event found" + + assert event["GuardianRemoved"][0]["guardian"] == guardian_address, "Wrong guardian address" + + if emitted_by is not None: + assert convert.to_address(event["GuardianRemoved"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_add_guardian_event(event: EventDict, guardian_address: str, emitted_by: Optional[str] = None): + _events_chain = ["LogScriptCall", "GuardianAdded", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("GuardianAdded") == 1 + + assert "GuardianAdded" in event, "No GuardianAdded event found" + + assert event["GuardianAdded"][0]["guardian"] == guardian_address, "Wrong guardian address" + + if emitted_by is not None: + assert convert.to_address(event["GuardianAdded"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def validate_staking_module_update_event( + event: EventDict, + module_id: int, + share_limit: int, + priority_share_threshold: int, + module_fee_points_bp: int, + treasury_fee_points_bp: int, + max_deposits_per_block: int, + min_deposit_block_distance: int, + emitted_by: Optional[str] = None +): + _events_chain = ["LogScriptCall", "StakingModuleShareLimitSet", "StakingModuleFeesSet", "StakingModuleMaxDepositsPerBlockSet", "StakingModuleMinDepositBlockDistanceSet", "ScriptResult", "Executed"] + validate_events_chain([e.name for e in event], _events_chain) + + assert event.count("LogScriptCall") == 1 + assert event.count("StakingModuleShareLimitSet") == 1 + assert event.count("StakingModuleFeesSet") == 1 + assert event.count("StakingModuleMaxDepositsPerBlockSet") == 1 + assert event.count("StakingModuleMinDepositBlockDistanceSet") == 1 + + assert "StakingModuleShareLimitSet" in event, "No StakingModuleShareLimitSet event found" + assert "StakingModuleFeesSet" in event, "No StakingModuleFeesSet event found" + assert "StakingModuleMaxDepositsPerBlockSet" in event, "No StakingModuleMaxDepositsPerBlockSet event found" + assert "StakingModuleMinDepositBlockDistanceSet" in event, "No StakingModuleMinDepositBlockDistanceSet event found" + + assert len(event["StakingModuleShareLimitSet"]) == 1, "Multiple StakingModuleShareLimitSet events found" + assert len(event["StakingModuleFeesSet"]) == 1, "Multiple StakingModuleFeesSet events found" + assert len( + event["StakingModuleMaxDepositsPerBlockSet"]) == 1, "Multiple StakingModuleMaxDepositsPerBlockSet events found" + assert len(event[ + "StakingModuleMinDepositBlockDistanceSet"]) == 1, "Multiple StakingModuleMinDepositBlockDistanceSet events found" + + assert event["StakingModuleShareLimitSet"][0]["stakingModuleId"] == module_id, "Wrong module ID" + assert event["StakingModuleShareLimitSet"][0]["stakeShareLimit"] == share_limit, "Wrong share limit" + assert event["StakingModuleShareLimitSet"][0][ + "priorityExitShareThreshold"] == priority_share_threshold, "Wrong priority threshold" + + assert event["StakingModuleFeesSet"][0]["stakingModuleFee"] == module_fee_points_bp, "Wrong fee points" + assert event["StakingModuleFeesSet"][0]["treasuryFee"] == treasury_fee_points_bp, "Wrong treasury fee points" + + assert event["StakingModuleMaxDepositsPerBlockSet"][0][ + "maxDepositsPerBlock"] == max_deposits_per_block, "Wrong max deposits" + + assert event["StakingModuleMinDepositBlockDistanceSet"][0][ + "minDepositBlockDistance"] == min_deposit_block_distance, "Wrong min distance" + + if emitted_by is not None: + assert convert.to_address(event["StakingModuleShareLimitSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + assert convert.to_address(event["StakingModuleFeesSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + assert convert.to_address(event["StakingModuleMaxDepositsPerBlockSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + assert convert.to_address( + event["StakingModuleMinDepositBlockDistanceSet"][0]["_emitted_by"]) == convert.to_address( + emitted_by), "Wrong event emitter" + + +def get_ossifiable_proxy_impl(proxy_address): + """Get implementation address from an OssifiableProxy""" + proxy = interface.OssifiableProxy(proxy_address) + return proxy.proxy__getImplementation() + + +def get_wv_contract_proxy_impl(proxy_address): + """Get implementation address from an WithdrawalContractProxy""" + proxy = interface.WithdrawalContractProxy(proxy_address) + return proxy.implementation() + + +def check_proxy_implementation(proxy_address, expected_impl): + """Check that proxy has expected implementation""" + actual_impl = get_ossifiable_proxy_impl(proxy_address) + assert actual_impl == expected_impl, f"Expected impl {expected_impl}, got {actual_impl}" + + +# ============================================================================ +# ============================== Import vote ================================= +# ============================================================================ +from archive.scripts.upgrade_tw_csm2 import start_vote, get_vote_items, encode_wv_proxy_upgrade_to + +# ============================================================================ +# ============================== Constants =================================== +# ============================================================================ +VOTING = "0x2e59A20f205bB85a89C53f1936454680651E618e" +EMERGENCY_PROTECTED_TIMELOCK = "0xCE0425301C85c5Ea2A0873A2dEe44d78E02D2316" +DUAL_GOVERNANCE = "0xC1db28B3301331277e307FDCfF8DE28242A4486E" +DUAL_GOVERNANCE_ADMIN_EXECUTOR = "0x23E0B465633FF5178808F4A75186E2F2F9537021" +AGENT = "0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c" +ARAGON_KERNEL = "0xb8FFC3Cd6e7Cf5a098A1c92F48009765B24088Dc" +STETH = "0xAE7ab96520DE3A18E5e111B5EaAb095312D7fE84" + +LIDO_LOCATOR = "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb" +VALIDATORS_EXIT_BUS_ORACLE = "0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e" +WITHDRAWAL_VAULT = "0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f" +ACCOUNTING_ORACLE = "0x852deD011285fe67063a08005c71a85690503Cee" +STAKING_ROUTER = "0xFdDf38947aFB03C621C71b06C9C70bce73f12999" +ACL = "0x9895F0F17cc1d1891b6f18ee0b483B6f221b37Bb" +NODE_OPERATORS_REGISTRY = "0x55032650b14df07b85bF18A3a3eC8E0Af2e028d5" +SIMPLE_DVT = "0xaE7B191A31f627b4eB1d4DaC64eaB9976995b433" +ORACLE_DAEMON_CONFIG = "0xbf05A929c3D7885a6aeAd833a992dA6E5ac23b09" +CSM_ADDRESS = "0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F" +DEPOSIT_SECURITY_MODULE = "0xfFA96D84dEF2EA035c7AB153D8B991128e3d72fD" +WITHDRAWAL_QUEUE = "0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1" +CS_ACCOUNTING_ADDRESS = "0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da" +CS_FEE_ORACLE_ADDRESS = "0x4D4074628678Bd302921c20573EEa1ed38DdF7FB" +CS_FEE_DISTRIBUTOR_ADDRESS = "0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0" +EASYTRACK = "0xF0211b7660680B49De1A7E9f25C65660F0a13Fea" + +# New core contracts implementations +LIDO_LOCATOR_IMPL = "0x2C298963FB763f74765829722a1ebe0784f4F5Cf" +ACCOUNTING_ORACLE_IMPL = "0xE9906E543274cebcd335d2C560094089e9547e8d" +VALIDATORS_EXIT_BUS_ORACLE_IMPL = "0x905A211eD6830Cfc95643f0bE2ff64E7f3bf9b94" +WITHDRAWAL_VAULT_IMPL = "0x7D2BAa6094E1C4B60Da4cbAF4A77C3f4694fD53D" +STAKING_ROUTER_IMPL = "0x226f9265CBC37231882b7409658C18bB7738173A" +NODE_OPERATORS_REGISTRY_IMPL = "0x6828b023e737f96B168aCd0b5c6351971a4F81aE" + +TRIGGERABLE_WITHDRAWALS_GATEWAY = "0xDC00116a0D3E064427dA2600449cfD2566B3037B" +VALIDATOR_EXIT_VERIFIER = "0xbDb567672c867DB533119C2dcD4FB9d8b44EC82f" + +# Add missing constants +OLD_GATE_SEAL_ADDRESS = "0xf9C9fDB4A5D2AA1D836D5370AB9b28BC1847e178" +NEW_WQ_GATE_SEAL = "0x8A854C4E750CDf24f138f34A9061b2f556066912" +NEW_TW_GATE_SEAL = "0xA6BC802fAa064414AA62117B4a53D27fFfF741F1" +RESEAL_MANAGER = "0x7914b5a1539b97Bd0bbd155757F25FD79A522d24" +DUAL_GOVERNANCE_TIME_CONSTRAINTS = "0x2a30F5aC03187674553024296bed35Aa49749DDa" + +# Add EasyTrack constants +EASYTRACK_EVMSCRIPT_EXECUTOR = "0xFE5986E06210aC1eCC1aDCafc0cc7f8D63B3F977" +EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0xB7668B5485d0f826B86a75b0115e088bB9ee03eE" +EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0x8aa34dAaF0fC263203A15Bcfa0Ed926D466e59F3" + +# Oracle consensus versions +AO_CONSENSUS_VERSION = 4 +VEBO_CONSENSUS_VERSION = 4 + +CSM_CONSENSUS_OLD_VERSION = 2 +CSM_CONSENSUS_NEW_VERSION = 3 + +EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS = 14 * 7200 + +NOR_EXIT_DEADLINE_IN_SEC = 345600 # 28800 slots + +# CSM +CS_MODULE_NEW_TARGET_SHARE_BP = 500 # 5% +CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP = 625 # 6.25% + +CS_ACCOUNTING_IMPL_V2_ADDRESS = "0x6f09d2426c7405C5546413e6059F884D2D03f449" +CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS = "0x5DCF7cF7c6645E9E822a379dF046a8b0390251A1" +CS_FEE_ORACLE_IMPL_V2_ADDRESS = "0xe0B234f99E413E27D9Bc31aBba9A49A3e570Da97" +CSM_IMPL_V2_ADDRESS = "0x1eB6d4da13ca9566c17F526aE0715325d7a07665" + +CS_EJECTOR_ADDRESS = "0xc72b58aa02E0e98cF8A4a0E9Dce75e763800802C" +CS_PERMISSIONLESS_GATE_ADDRESS = "0xcF33a38111d0B1246A3F38a838fb41D626B454f0" +CS_VETTED_GATE_ADDRESS = "0xB314D4A76C457c93150d308787939063F4Cc67E0" +CS_VERIFIER_V2_ADDRESS = "0xdC5FE1782B6943f318E05230d688713a560063DC" +CS_VERIFIER_ADDRESS_OLD = "0xeC6Cc185f671F627fb9b6f06C8772755F587b05d" +CS_GATE_SEAL_V2_ADDRESS = "0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3" + +# Bond curves for CS Accounting +CS_CURVES = [ + ([1, 2.4 * 10 ** 18], [2, 1.3 * 10 ** 18]), # Default Curve + ([1, 1.5 * 10 ** 18], [2, 1.3 * 10 ** 18]), # Legacy EA Curve +] +CS_ICS_GATE_BOND_CURVE = ([1, 1.5 * 10 ** 18], [2, 1.3 * 10 ** 18]) # Identified Community Stakers Gate Bond Curve + +# CSM committee and config addresses (imported from config in actual script) +CSM_COMMITTEE_MS = "0xC52fC3081123073078698F1EAc2f1Dc7Bd71880f" +CS_GATE_SEAL_ADDRESS = "0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0" + +# CSM staking module constants (from config) +CS_ORACLE_EPOCHS_PER_FRAME = 225 * 28 # 28 days +CS_MODULE_ID = 3 +CS_MODULE_NAME = "Community Staking" +CS_MODULE_MODULE_FEE_BP = 600 +CS_MODULE_TREASURY_FEE_BP = 400 +CS_MODULE_TARGET_SHARE_BP = 300 # Updated from 200 to 300 in vote 2025/07/16 +CS_MODULE_PRIORITY_EXIT_SHARE_THRESHOLD = 375 # Updated from 250 to 375 in vote 2025/07/16 +CS_MODULE_MAX_DEPOSITS_PER_BLOCK = 30 +CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE = 25 + +# Contract versions expected after upgrade +CSM_V2_VERSION = 2 +CS_ACCOUNTING_V2_VERSION = 2 +CS_FEE_ORACLE_V2_VERSION = 2 +CS_FEE_DISTRIBUTOR_V2_VERSION = 2 + +EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY = "0xBc5642bDD6F2a54b01A75605aAe9143525D97308" + +EXPECTED_VOTE_ID = 192 +EXPECTED_DG_PROPOSAL_ID = 5 +EXPECTED_VOTE_EVENTS_COUNT = 4 +EXPECTED_DG_EVENTS_FROM_AGENT = 69 +EXPECTED_DG_EVENTS_COUNT = 71 +IPFS_DESCRIPTION_HASH = "bafkreicbufoefjutdeadrzhbqnxgonc5rljlwyyrftytxkykiufkpmc3ii" + +NETHERMIND_NO_ID = 25 +NETHERMIND_NO_NAME_OLD = "Nethermind" +NETHERMIND_NO_NAME_NEW = "Twinstake" +NETHERMIND_NO_STAKING_REWARDS_ADDRESS_OLD = "0x237DeE529A47750bEcdFa8A59a1D766e3e7B5F91" +NETHERMIND_NO_STAKING_REWARDS_ADDRESS_NEW = "0x36201ed66DbC284132046ee8d99272F8eEeb24c8" + +NODE_OPERATORS_REGISTRY_ARAGON_APP_ID = "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d" +SIMPLE_DVT_ARAGON_APP_ID = "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4" + +OLD_KILN_ADDRESS = "0x14D5d5B71E048d2D75a39FfC5B407e3a3AB6F314" +NEW_KILN_ADDRESS = "0x6d22aE126eB2c37F67a1391B37FF4f2863e61389" +DSM_QUORUM_SIZE = 4 + +UTC13 = 60 * 60 * 13 +UTC19 = 60 * 60 * 19 +MAX_VALIDATORS_PER_REPORT = 600 +MAX_EXIT_REQUESTS_LIMIT = 11200 +EXITS_PER_FRAME = 1 +FRAME_DURATION_IN_SEC = 48 + +import pytest +from utils.agent import agent_forward +from utils.permissions import encode_oz_grant_role, encode_oz_revoke_role +from utils.node_operators import encode_set_node_operator_name, encode_set_node_operator_reward_address + + +@pytest.fixture(scope="module") +def dual_governance_proposal_calls(): + """Returns list of dual governance proposal calls for events checking""" + + # Helper function to encode proxy upgrades + def encode_proxy_upgrade_to(proxy_contract, new_impl_address): + return (proxy_contract.address, proxy_contract.proxy__upgradeTo.encode_input(new_impl_address)) + + # Helper function to encode oracle consensus upgrades + def encode_oracle_upgrade_consensus(oracle_contract, new_version): + return (oracle_contract.address, oracle_contract.setConsensusVersion.encode_input(new_version)) + + # Cast contracts to OssifiableProxy interface to access proxy methods + _ = interface.StETH(STETH) # Loading ABI to parse DG events + lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + vebo_proxy = interface.OssifiableProxy(VALIDATORS_EXIT_BUS_ORACLE) + validators_exit_bus_oracle = interface.ValidatorsExitBusOracle(VALIDATORS_EXIT_BUS_ORACLE) + withdrawal_vault_proxy = interface.OssifiableProxy(WITHDRAWAL_VAULT) + accounting_oracle_proxy = interface.OssifiableProxy(ACCOUNTING_ORACLE) + staking_router_proxy = interface.OssifiableProxy(STAKING_ROUTER) + csm_proxy = interface.OssifiableProxy(CSM_ADDRESS) + cs_accounting_proxy = interface.OssifiableProxy(CS_ACCOUNTING_ADDRESS) + cs_fee_oracle_proxy = interface.OssifiableProxy(CS_FEE_ORACLE_ADDRESS) + cs_fee_distributor_proxy = interface.OssifiableProxy(CS_FEE_DISTRIBUTOR_ADDRESS) + agent = interface.Agent(AGENT) + withdrawal_vault = interface.WithdrawalVault(WITHDRAWAL_VAULT) + accounting_oracle = interface.AccountingOracle(ACCOUNTING_ORACLE) + staking_router = interface.StakingRouter(STAKING_ROUTER) + acl = interface.ACL(ACL) + kernel = interface.Kernel(ARAGON_KERNEL) + nor = interface.NodeOperatorsRegistry(NODE_OPERATORS_REGISTRY) + simple_dvt = interface.SimpleDVT(SIMPLE_DVT) + oracle_daemon_config = interface.OracleDaemonConfig(ORACLE_DAEMON_CONFIG) + csm = interface.CSModule(CSM_ADDRESS) + dsm = interface.DepositSecurityModule(DEPOSIT_SECURITY_MODULE) + withdrawal_queue = interface.WithdrawalQueueERC721(WITHDRAWAL_QUEUE) + cs_accounting = interface.CSAccounting(CS_ACCOUNTING_ADDRESS) + cs_fee_oracle = interface.CSFeeOracle(CS_FEE_ORACLE_ADDRESS) + cs_fee_distributor = interface.CSFeeDistributor(CS_FEE_DISTRIBUTOR_ADDRESS) + easy_track = interface.EasyTrack(EASYTRACK) + + # Create all the dual governance calls that match the voting script + dg_items = [ + # 1.1. Update locator implementation + agent_forward([encode_proxy_upgrade_to(lido_locator_proxy, LIDO_LOCATOR_IMPL)]), + + # 1.2. Update VEBO implementation + agent_forward([encode_proxy_upgrade_to(vebo_proxy, VALIDATORS_EXIT_BUS_ORACLE_IMPL)]), + + # 1.3. Call finalizeUpgrade_v2 on VEBO + agent_forward([ + (validators_exit_bus_oracle.address, + validators_exit_bus_oracle.finalizeUpgrade_v2.encode_input(MAX_VALIDATORS_PER_REPORT, + MAX_EXIT_REQUESTS_LIMIT, + EXITS_PER_FRAME, + FRAME_DURATION_IN_SEC)) + ]), + + # 1.4. Grant VEBO role MANAGE_CONSENSUS_VERSION_ROLE to the AGENT + agent_forward([ + encode_oz_grant_role( + contract=vebo_proxy, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + grant_to=agent + ) + ]), + + # 1.5. Bump VEBO consensus version to 4 + agent_forward([encode_oracle_upgrade_consensus(validators_exit_bus_oracle, VEBO_CONSENSUS_VERSION)]), + + # 1.6. Revoke VEBO role MANAGE_CONSENSUS_VERSION_ROLE from the AGENT + agent_forward([ + encode_oz_revoke_role( + contract=vebo_proxy, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + revoke_from=agent + ) + ]), + + # 1.7. Grant SUBMIT_REPORT_HASH_ROLE on VEBO to EasyTrack executor + agent_forward([ + encode_oz_grant_role( + contract=vebo_proxy, + role_name="SUBMIT_REPORT_HASH_ROLE", + grant_to=EASYTRACK_EVMSCRIPT_EXECUTOR + ) + ]), + + # 1.8. Grant TWG role ADD_FULL_WITHDRAWAL_REQUEST_ROLE to CS Ejector + agent_forward([ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="ADD_FULL_WITHDRAWAL_REQUEST_ROLE", + grant_to=CS_EJECTOR_ADDRESS + ) + ]), + + # 1.9. Grant TWG role ADD_FULL_WITHDRAWAL_REQUEST_ROLE to VEBO + agent_forward([ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="ADD_FULL_WITHDRAWAL_REQUEST_ROLE", + grant_to=vebo_proxy.address + ) + ]), + + # 1.10. Connect TWG to Dual Governance tiebreaker + ( + interface.DualGovernance(DUAL_GOVERNANCE).address, + interface.DualGovernance(DUAL_GOVERNANCE).addTiebreakerSealableWithdrawalBlocker.encode_input( + TRIGGERABLE_WITHDRAWALS_GATEWAY) + ), + + # 1.11. Update WithdrawalVault implementation + agent_forward([encode_wv_proxy_upgrade_to(withdrawal_vault_proxy, WITHDRAWAL_VAULT_IMPL)]), + + # 1.12. Call finalizeUpgrade_v2() on WithdrawalVault + agent_forward([ + (withdrawal_vault.address, withdrawal_vault.finalizeUpgrade_v2.encode_input()) + ]), + + # 1.13. Update Accounting Oracle implementation + agent_forward([encode_proxy_upgrade_to(accounting_oracle_proxy, ACCOUNTING_ORACLE_IMPL)]), + + # 1.14. Grant AO MANAGE_CONSENSUS_VERSION_ROLE to the AGENT + agent_forward([ + encode_oz_grant_role( + contract=accounting_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + grant_to=agent + ) + ]), + + # 1.15. Bump AO consensus version to 4 + agent_forward([encode_oracle_upgrade_consensus(accounting_oracle, AO_CONSENSUS_VERSION)]), + + # 1.16. Revoke AO MANAGE_CONSENSUS_VERSION_ROLE from the AGENT + agent_forward([ + encode_oz_revoke_role( + contract=accounting_oracle, + role_name="MANAGE_CONSENSUS_VERSION_ROLE", + revoke_from=agent + ) + ]), + + # 1.17. Call finalizeUpgrade_v3() on AO + agent_forward([ + (accounting_oracle.address, accounting_oracle.finalizeUpgrade_v3.encode_input()) + ]), + + # 1.18. Update SR implementation + agent_forward([encode_proxy_upgrade_to(staking_router_proxy, STAKING_ROUTER_IMPL)]), + + # 1.19. Call finalizeUpgrade_v3() on SR + agent_forward([ + (staking_router.address, staking_router.finalizeUpgrade_v3.encode_input()) + ]), + + # 1.20. Grant SR role REPORT_VALIDATOR_EXITING_STATUS_ROLE to ValidatorExitVerifier + agent_forward([ + encode_oz_grant_role( + contract=staking_router, + role_name="REPORT_VALIDATOR_EXITING_STATUS_ROLE", + grant_to=VALIDATOR_EXIT_VERIFIER + ) + ]), + + # 1.21. Grant SR role REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE to TWG + agent_forward([ + encode_oz_grant_role( + contract=staking_router, + role_name="REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE", + grant_to=TRIGGERABLE_WITHDRAWALS_GATEWAY + ) + ]), + + # 1.22-1.27: Kernel and registry upgrades + # 1.22. Grant APP_MANAGER_ROLE role to the AGENT + agent_forward([ + (acl.address, + acl.grantPermission.encode_input( + AGENT, + ARAGON_KERNEL, + web3.keccak(text="APP_MANAGER_ROLE") + )) + ]), + + # 1.23. Update NodeOperatorsRegistry implementation + agent_forward([ + (kernel.address, + kernel.setApp.encode_input( + kernel.APP_BASES_NAMESPACE(), + NODE_OPERATORS_REGISTRY_ARAGON_APP_ID, + NODE_OPERATORS_REGISTRY_IMPL + )) + ]), + + # 1.24. Call finalizeUpgrade_v4 on Curated Staking Module + agent_forward([ + (interface.NodeOperatorsRegistry(nor).address, + interface.NodeOperatorsRegistry(nor).finalizeUpgrade_v4.encode_input( + NOR_EXIT_DEADLINE_IN_SEC)) + ]), + + # 1.25. Update SDVT implementation + agent_forward([ + (kernel.address, + kernel.setApp.encode_input( + kernel.APP_BASES_NAMESPACE(), + SIMPLE_DVT_ARAGON_APP_ID, + NODE_OPERATORS_REGISTRY_IMPL + )) + ]), + + # 1.26. Call finalizeUpgrade_v4 on SDVT + agent_forward([ + (interface.NodeOperatorsRegistry(simple_dvt).address, + interface.NodeOperatorsRegistry(simple_dvt).finalizeUpgrade_v4.encode_input( + NOR_EXIT_DEADLINE_IN_SEC)) + ]), + + # 1.27. Revoke APP_MANAGER_ROLE role from the AGENT + agent_forward([ + (acl.address, + acl.revokePermission.encode_input( + AGENT, + ARAGON_KERNEL, + web3.keccak(text="APP_MANAGER_ROLE") + )) + ]), + + # 1.28-1.33: Oracle daemon config changes + agent_forward([ + encode_oz_grant_role( + contract=oracle_daemon_config, + role_name="CONFIG_MANAGER_ROLE", + grant_to=agent + ) + ]), + + agent_forward([ + (oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input('NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP')) + ]), + + agent_forward([ + (oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input('VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS')) + ]), + + agent_forward([ + (oracle_daemon_config.address, + oracle_daemon_config.unset.encode_input('VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS')) + ]), + + agent_forward([ + (oracle_daemon_config.address, + oracle_daemon_config.set.encode_input('EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS', + EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS)) + ]), + + agent_forward([ + encode_oz_revoke_role( + contract=oracle_daemon_config, + role_name="CONFIG_MANAGER_ROLE", + revoke_from=agent + ) + ]), + + # CSM upgrades and role changes (steps 1.34-1.59) + # 1.34. Upgrade CSM implementation on proxy + agent_forward([encode_proxy_upgrade_to(csm_proxy, CSM_IMPL_V2_ADDRESS)]), + + # 1.35. Call finalizeUpgradeV2() on CSM contract + agent_forward([(csm.address, csm.finalizeUpgradeV2.encode_input())]), + + # 1.36. Upgrade CSAccounting implementation on proxy + agent_forward([encode_proxy_upgrade_to(cs_accounting_proxy, CS_ACCOUNTING_IMPL_V2_ADDRESS)]), + + # 1.37. Call finalizeUpgradeV2(bondCurves) on CSAccounting contract + agent_forward([ + (cs_accounting.address, + cs_accounting.finalizeUpgradeV2.encode_input(CS_CURVES)) + ]), + + # 1.38. Upgrade CSFeeOracle implementation on proxy + agent_forward([encode_proxy_upgrade_to(cs_fee_oracle_proxy, CS_FEE_ORACLE_IMPL_V2_ADDRESS)]), + + # 1.39. Call finalizeUpgradeV2(consensusVersion) on CSFeeOracle contract + agent_forward([ + (cs_fee_oracle.address, cs_fee_oracle.finalizeUpgradeV2.encode_input(CSM_CONSENSUS_NEW_VERSION)) + ]), + + # 1.40. Upgrade CSFeeDistributor implementation on proxy + agent_forward([encode_proxy_upgrade_to(cs_fee_distributor_proxy, CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS)]), + + # 1.41. Call finalizeUpgradeV2(admin) on CSFeeDistributor contract + agent_forward([ + (cs_fee_distributor.address, cs_fee_distributor.finalizeUpgradeV2.encode_input(agent)) + ]), + + # 1.42. Revoke CSAccounting role SET_BOND_CURVE_ROLE from the CSM contract + agent_forward([ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="SET_BOND_CURVE_ROLE", + revoke_from=csm + ) + ]), + + # 1.43. Revoke CSAccounting role RESET_BOND_CURVE_ROLE from the CSM contract + agent_forward([ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="RESET_BOND_CURVE_ROLE", + revoke_from=csm + ) + ]), + + # 1.44. Revoke CSAccounting role RESET_BOND_CURVE_ROLE from the CSM committee + agent_forward([ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="RESET_BOND_CURVE_ROLE", + revoke_from=CSM_COMMITTEE_MS + ) + ]), + + # 1.45. Grant CSM role CREATE_NODE_OPERATOR_ROLE for the permissionless gate + agent_forward([ + encode_oz_grant_role( + contract=csm, + role_name="CREATE_NODE_OPERATOR_ROLE", + grant_to=CS_PERMISSIONLESS_GATE_ADDRESS + ) + ]), + + # 1.46. Grant CSM role CREATE_NODE_OPERATOR_ROLE for the vetted gate + agent_forward([ + encode_oz_grant_role( + contract=csm, + role_name="CREATE_NODE_OPERATOR_ROLE", + grant_to=CS_VETTED_GATE_ADDRESS + ) + ]), + + # 1.47. Grant CSAccounting role SET_BOND_CURVE_ROLE for the vetted gate + agent_forward([ + encode_oz_grant_role( + contract=cs_accounting, + role_name="SET_BOND_CURVE_ROLE", + grant_to=CS_VETTED_GATE_ADDRESS + ) + ]), + + # 1.48. Revoke role VERIFIER_ROLE from the previous instance of the Verifier contract + agent_forward([ + encode_oz_revoke_role( + contract=csm, + role_name="VERIFIER_ROLE", + revoke_from=CS_VERIFIER_ADDRESS_OLD + ) + ]), + + # 1.49. Grant role VERIFIER_ROLE to the new instance of the Verifier contract + agent_forward([ + encode_oz_grant_role( + contract=csm, + role_name="VERIFIER_ROLE", + grant_to=CS_VERIFIER_V2_ADDRESS + ) + ]), + + # 1.50. Revoke CSM role PAUSE_ROLE from the previous GateSeal instance + agent_forward([ + encode_oz_revoke_role( + contract=csm, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS + ) + ]), + + # 1.51. Revoke CSAccounting role PAUSE_ROLE from the previous GateSeal instance + agent_forward([ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS + ) + ]), + + # 1.52. Revoke CSFeeOracle role PAUSE_ROLE from the previous GateSeal instance + agent_forward([ + encode_oz_revoke_role( + contract=cs_fee_oracle, + role_name="PAUSE_ROLE", + revoke_from=CS_GATE_SEAL_ADDRESS + ) + ]), + + # 1.53. Grant CSM role PAUSE_ROLE for the new GateSeal instance + agent_forward([ + encode_oz_grant_role( + contract=csm, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS + ) + ]), + + # 1.54. Grant CSAccounting role PAUSE_ROLE for the new GateSeal instance + agent_forward([ + encode_oz_grant_role( + contract=cs_accounting, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS + ) + ]), + + # 1.55. Grant CSFeeOracle role PAUSE_ROLE for the new GateSeal instance + agent_forward([ + encode_oz_grant_role( + contract=cs_fee_oracle, + role_name="PAUSE_ROLE", + grant_to=CS_GATE_SEAL_V2_ADDRESS + ) + ]), + + # 1.56. Grant MANAGE_BOND_CURVES_ROLE to the AGENT + agent_forward([ + encode_oz_grant_role( + contract=cs_accounting, + role_name="MANAGE_BOND_CURVES_ROLE", + grant_to=agent + ) + ]), + + # 1.57. Add Identified Community Stakers Gate Bond Curve + agent_forward([ + (cs_accounting.address, cs_accounting.addBondCurve.encode_input(CS_ICS_GATE_BOND_CURVE)) + ]), + + # 1.58. Revoke MANAGE_BOND_CURVES_ROLE from the AGENT + agent_forward([ + encode_oz_revoke_role( + contract=cs_accounting, + role_name="MANAGE_BOND_CURVES_ROLE", + revoke_from=agent + ) + ]), + + # 1.59. Increase CSM share in Staking Router from 3% to 5% + agent_forward([ + (staking_router.address, + staking_router.updateStakingModule.encode_input( + CS_MODULE_ID, + CS_MODULE_NEW_TARGET_SHARE_BP, + CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP, + CS_MODULE_MODULE_FEE_BP, + CS_MODULE_TREASURY_FEE_BP, + CS_MODULE_MAX_DEPOSITS_PER_BLOCK, + CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE + )) + ]), + + # Gate seals and node operator changes (steps 60-68) + # 1.60. Revoke PAUSE_ROLE on WithdrawalQueue from the old GateSeal + agent_forward([ + encode_oz_revoke_role( + contract=withdrawal_queue, + role_name="PAUSE_ROLE", + revoke_from=OLD_GATE_SEAL_ADDRESS + ) + ]), + + # 1.61. Revoke PAUSE_ROLE on ValidatorsExitBusOracle from the old GateSeal + agent_forward([ + encode_oz_revoke_role( + contract=vebo_proxy, + role_name="PAUSE_ROLE", + revoke_from=OLD_GATE_SEAL_ADDRESS + ) + ]), + + # 1.62. Grant PAUSE_ROLE on WithdrawalQueue to the new WithdrawalQueue GateSeal + agent_forward([ + encode_oz_grant_role( + contract=withdrawal_queue, + role_name="PAUSE_ROLE", + grant_to=NEW_WQ_GATE_SEAL + ) + ]), + + # 1.63. Grant PAUSE_ROLE on ValidatorsExitBusOracle to the new Triggerable Withdrawals GateSeal + agent_forward([ + encode_oz_grant_role( + contract=vebo_proxy, + role_name="PAUSE_ROLE", + grant_to=NEW_TW_GATE_SEAL + ) + ]), + + # 1.64. Grant PAUSE_ROLE on TriggerableWithdrawalsGateway to the new Triggerable Withdrawals GateSeal + agent_forward([ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="PAUSE_ROLE", + grant_to=NEW_TW_GATE_SEAL + ) + ]), + + # 1.65. Grant PAUSE_ROLE on TriggerableWithdrawalsGateway to ResealManager + agent_forward([ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="PAUSE_ROLE", + grant_to=RESEAL_MANAGER + ) + ]), + + # 1.66. Grant RESUME_ROLE on TriggerableWithdrawalsGateway to ResealManager + agent_forward([ + encode_oz_grant_role( + contract=interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY), + role_name="RESUME_ROLE", + grant_to=RESEAL_MANAGER + ) + ]), + + # Node operator changes + # 1.67. Rename Node Operator ID 25 from Nethermind to Twinstake + agent_forward( + [encode_set_node_operator_name(id=25, name=NETHERMIND_NO_NAME_NEW, registry=nor)]), + # 1.68. Change Node Operator ID 25 reward address + agent_forward([encode_set_node_operator_reward_address( + id=25, + rewardAddress=NETHERMIND_NO_STAKING_REWARDS_ADDRESS_NEW, + registry=nor, + )]), + + # 1.69. Remove Kiln guardian + agent_forward([ + encode_remove_guardian(dsm=dsm, guardian_address=OLD_KILN_ADDRESS, quorum_size=DSM_QUORUM_SIZE), + ]), + # 1.70. Add new Kiln guardian + agent_forward([ + encode_add_guardian(dsm=dsm, guardian_address=NEW_KILN_ADDRESS, quorum_size=DSM_QUORUM_SIZE), + ]), + # 1.71. Set time constraints for execution (13:00 to 19:00 UTC) + ( + DUAL_GOVERNANCE_TIME_CONSTRAINTS, + interface.TimeConstraints(DUAL_GOVERNANCE_TIME_CONSTRAINTS).checkTimeWithinDayTimeAndEmit.encode_input( + UTC13, # 13:00 UTC + UTC19 # 19:00 UTC + ), + ), + ] + + # Convert each dg_item to the expected format + proposal_calls = [] + for dg_item in dg_items: + target, data = dg_item # agent_forward returns (target, data) + proposal_calls.append({ + "target": target, + "value": 0, + "data": data + }) + + return proposal_calls + + +def test_vote(helpers, accounts, ldo_holder, vote_ids_from_env, stranger, dual_governance_proposal_calls): + # Cast contracts to OssifiableProxy interface to access proxy methods + _ = interface.StETH(STETH) # Loading ABI to parse DG events + lido_locator_proxy = interface.OssifiableProxy(LIDO_LOCATOR) + vebo_proxy = interface.OssifiableProxy(VALIDATORS_EXIT_BUS_ORACLE) + validators_exit_bus_oracle = interface.ValidatorsExitBusOracle(VALIDATORS_EXIT_BUS_ORACLE) + agent = interface.Agent(AGENT) + withdrawal_vault = interface.WithdrawalVault(WITHDRAWAL_VAULT) + accounting_oracle = interface.AccountingOracle(ACCOUNTING_ORACLE) + staking_router = interface.StakingRouter(STAKING_ROUTER) + acl = interface.ACL(ACL) + kernel = interface.Kernel(ARAGON_KERNEL) + nor = interface.NodeOperatorsRegistry(NODE_OPERATORS_REGISTRY) + simple_dvt = interface.SimpleDVT(SIMPLE_DVT) + oracle_daemon_config = interface.OracleDaemonConfig(ORACLE_DAEMON_CONFIG) + csm = interface.CSModule(CSM_ADDRESS) + dsm = interface.DepositSecurityModule(DEPOSIT_SECURITY_MODULE) + withdrawal_queue = interface.WithdrawalQueueERC721(WITHDRAWAL_QUEUE) + cs_accounting = interface.CSAccounting(CS_ACCOUNTING_ADDRESS) + cs_fee_oracle = interface.CSFeeOracle(CS_FEE_ORACLE_ADDRESS) + cs_fee_distributor = interface.CSFeeDistributor(CS_FEE_DISTRIBUTOR_ADDRESS) + easy_track = interface.EasyTrack(EASYTRACK) + # Save original implementations for comparison + locator_impl_before = get_ossifiable_proxy_impl(LIDO_LOCATOR) + accounting_oracle_impl_before = get_ossifiable_proxy_impl(ACCOUNTING_ORACLE) + vebo_impl_before = get_ossifiable_proxy_impl(VALIDATORS_EXIT_BUS_ORACLE) + withdrawal_vault_impl_before = get_wv_contract_proxy_impl(WITHDRAWAL_VAULT) + staking_router_impl_before = get_ossifiable_proxy_impl(STAKING_ROUTER) + + csm_impl_before = get_ossifiable_proxy_impl(CSM_ADDRESS) + cs_accounting_impl_before = get_ossifiable_proxy_impl(CS_ACCOUNTING_ADDRESS) + cs_fee_oracle_impl_before = get_ossifiable_proxy_impl(CS_FEE_ORACLE_ADDRESS) + cs_fee_distributor_impl_before = get_ossifiable_proxy_impl(CS_FEE_DISTRIBUTOR_ADDRESS) + + voting = interface.Voting(VOTING) + timelock = interface.EmergencyProtectedTimelock(EMERGENCY_PROTECTED_TIMELOCK) + dual_governance = interface.DualGovernance(DUAL_GOVERNANCE) + + # Not yet used by the protocol, but needed for the test + triggerable_withdrawals_gateway = interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY) + cs_ejector = interface.CSEjector(CS_EJECTOR_ADDRESS) + cs_permissionless_gate = interface.CSPermissionlessGate(CS_PERMISSIONLESS_GATE_ADDRESS) + cs_vetted_gate = interface.CSVettedGate(CS_VETTED_GATE_ADDRESS) + cs_verifier_v2 = interface.CSVerifierV2(CS_VERIFIER_V2_ADDRESS) + + no_registry = interface.NodeOperatorsRegistry(NODE_OPERATORS_REGISTRY) + + # START VOTE + if vote_ids_from_env: + vote_id = vote_ids_from_env[0] + if EXPECTED_VOTE_ID is not None: + assert vote_id == EXPECTED_VOTE_ID + elif EXPECTED_VOTE_ID is not None and voting.votesLength() > EXPECTED_VOTE_ID: + vote_id = EXPECTED_VOTE_ID + else: + vote_id, _ = start_vote({"from": ldo_holder}, silent=True) + + _, call_script_items = get_vote_items() + onchain_script = voting.getVote(vote_id)["script"] + assert onchain_script == encode_call_script(call_script_items) + + # ============================================================================ + # ============================= Execute Vote ============================== + # ========================================================================= + is_executed = voting.getVote(vote_id)["executed"] + if not is_executed: + # ======================================================================= + # ========================= Before voting checks ======================== + # ======================================================================= + # Step 2: Add EasyTrack factory for CSSetVettedGateTree + initial_factories = easy_track.getEVMScriptFactories() + assert EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY not in initial_factories, "EasyTrack should not have CSMSetVettedGateTree factory before vote" + + # Steps 3-4: Validate EasyTrack factories for validator exit request hashes + assert EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY not in initial_factories, "EasyTrack should not have SDVT validator exit request hashes factory before vote" + assert EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY not in initial_factories, "EasyTrack should not have Curated validator exit request hashes factory before vote" + + assert get_lido_vote_cid_from_str(find_metadata_by_vote_id(vote_id)) == IPFS_DESCRIPTION_HASH + + vote_tx: TransactionReceipt = helpers.execute_vote(vote_id=vote_id, accounts=accounts, dao_voting=voting) + + # ======================================================================= + # ========================= After voting checks ========================= + # ======================================================================= + # Step 2: Add EasyTrack factory for CSSetVettedGateTree + new_factories = easy_track.getEVMScriptFactories() + assert EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY in new_factories, "EasyTrack should have CSSetVettedGateTree factory after vote" + + # Steps 3-4: Validate EasyTrack factories for validator exit request hashes + assert EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY in new_factories, "EasyTrack should have SDVT validator exit request hashes factory after vote" + assert EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY in new_factories, "EasyTrack should have Curated validator exit request hashes factory after vote" + + # --- VALIDATE EVENTS --- + vote_events = group_voting_events_from_receipt(vote_tx) + # Validate voting events structure + dg_voting_event, dg_bypass_voting_event1, dg_bypass_voting_event2, dg_bypass_voting_event3 = vote_events + + assert len(vote_events) == EXPECTED_VOTE_EVENTS_COUNT, "Unexpected number of dual governance events" + assert count_vote_items_by_events(vote_tx, voting.address) == EXPECTED_VOTE_EVENTS_COUNT + if EXPECTED_DG_PROPOSAL_ID is not None: + assert EXPECTED_DG_PROPOSAL_ID == timelock.getProposalsCount() + + # Validate DG Proposal Submit event + validate_dual_governance_submit_event( + vote_events[0], + proposal_id=EXPECTED_DG_PROPOSAL_ID, + proposer=VOTING, + executor=DUAL_GOVERNANCE_ADMIN_EXECUTOR, + metadata="Upgrade to CSM v2, enable Triggerable Withdrawals, update the reward address and name for Node Operator ID 25 `Nethermind`, rotate Kiln Deposit Security Committee address", + proposal_calls=dual_governance_proposal_calls, + emitted_by=[EMERGENCY_PROTECTED_TIMELOCK, DUAL_GOVERNANCE], + ) + + # Validate EasyTrack bypass events for new factories + validate_evmscript_factory_added_event( + event=dg_bypass_voting_event1, + p=EVMScriptFactoryAdded( + factory_addr=EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY, + permissions=create_permissions(interface.CSVettedGate(CS_VETTED_GATE_ADDRESS), "setTreeParams") + ), + emitted_by=easy_track, + ) + + validate_evmscript_factory_added_event( + event=dg_bypass_voting_event2, + p=EVMScriptFactoryAdded( + factory_addr=EASYTRACK_SDVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY, + permissions=create_permissions(validators_exit_bus_oracle, "submitExitRequestsHash") + ), + emitted_by=easy_track, + ) + + validate_evmscript_factory_added_event( + event=dg_bypass_voting_event3, + p=EVMScriptFactoryAdded( + factory_addr=EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY, + permissions=create_permissions(validators_exit_bus_oracle, "submitExitRequestsHash") + ), + emitted_by=easy_track, + ) + + if EXPECTED_DG_PROPOSAL_ID is not None: + details = timelock.getProposalDetails(EXPECTED_DG_PROPOSAL_ID) + if details["status"] != PROPOSAL_STATUS["executed"]: + # ========================================================================= + # ================== DG before proposal executed checks =================== + # ========================================================================= + # Step 1.1: Check Lido Locator implementation initial state + assert locator_impl_before != LIDO_LOCATOR_IMPL, "Locator implementation should be different before upgrade" + + # Step 1.2: Check VEBO implementation initial state + assert vebo_impl_before != VALIDATORS_EXIT_BUS_ORACLE_IMPL, "VEBO implementation should be different before upgrade" + + # Steps 1.4-1.6: Check VEBO consensus version management + initial_vebo_consensus_version = validators_exit_bus_oracle.getConsensusVersion() + assert initial_vebo_consensus_version < VEBO_CONSENSUS_VERSION, f"VEBO consensus version should be less than {VEBO_CONSENSUS_VERSION}" + + manage_consensus_role = validators_exit_bus_oracle.MANAGE_CONSENSUS_VERSION_ROLE() + assert not validators_exit_bus_oracle.hasRole(manage_consensus_role, agent), "Agent should not have MANAGE_CONSENSUS_ROLE before upgrade" + + # Step 1.7: Check EasyTrack VEB SUBMIT_REPORT_HASH_ROLE initial state + submit_report_hash_role = web3.keccak(text="SUBMIT_REPORT_HASH_ROLE") + assert not validators_exit_bus_oracle.hasRole(submit_report_hash_role, + EASYTRACK_EVMSCRIPT_EXECUTOR), "EasyTrack executor should not have SUBMIT_REPORT_HASH_ROLE on VEBO before upgrade" + + # Step 1.8: Check TWG role for CS Ejector initial state + add_full_withdrawal_request_role = triggerable_withdrawals_gateway.ADD_FULL_WITHDRAWAL_REQUEST_ROLE() + assert not triggerable_withdrawals_gateway.hasRole(add_full_withdrawal_request_role, + cs_ejector), "CS Ejector should not have ADD_FULL_WITHDRAWAL_REQUEST_ROLE before upgrade" + + # Step 1.9: Check TWG role for VEB initial state + assert not triggerable_withdrawals_gateway.hasRole(add_full_withdrawal_request_role, + vebo_proxy), "VEBO should not have ADD_FULL_WITHDRAWAL_REQUEST_ROLE before upgrade" + + # Step 1.10: Check DualGovernance tiebreaker initial state + tiebreaker_details = dual_governance.getTiebreakerDetails() + initial_tiebreakers = tiebreaker_details[3] # sealableWithdrawalBlockers + assert TRIGGERABLE_WITHDRAWALS_GATEWAY not in initial_tiebreakers, "TWG should not be in tiebreaker list before upgrade" + + # Step 1.11: Check Withdrawal Vault implementation initial state + assert withdrawal_vault_impl_before != WITHDRAWAL_VAULT_IMPL, "Withdrawal Vault implementation should be different before upgrade" + + # Step 1.12: Withdrawal Vault finalizeUpgrade_v2 check is done post-execution + assert withdrawal_vault.getContractVersion() == 1, "Withdrawal Vault version should be 1 before upgrade" + + # Step 1.13: Check Accounting Oracle implementation initial state + assert accounting_oracle_impl_before != ACCOUNTING_ORACLE_IMPL, "Accounting Oracle implementation should be different before upgrade" + + # Steps 1.14-1.16: Check AO consensus version management + initial_ao_consensus_version = accounting_oracle.getConsensusVersion() + assert initial_ao_consensus_version < AO_CONSENSUS_VERSION, f"AO consensus version should be less than {AO_CONSENSUS_VERSION}" + assert not accounting_oracle.hasRole(accounting_oracle.MANAGE_CONSENSUS_VERSION_ROLE(), + agent), "Agent should not have MANAGE_CONSENSUS_VERSION_ROLE on AO before upgrade" + + # Step 1.17: Check AO version before finalizeUpgrade_v3 + assert accounting_oracle.getContractVersion() == 2, "AO contract version should be 2 before finalizeUpgrade_v3" + + # Step 1.18: Check Staking Router implementation initial state + assert staking_router_impl_before != STAKING_ROUTER_IMPL, "Staking Router implementation should be different before upgrade" + + # Step 1.19: Check SR version (before finalizeUpgrade_v3) + assert staking_router.getContractVersion() == 2, "Staking Router version should be 2 before upgrade" + + # Step 1.22: Check APP_MANAGER_ROLE initial state + app_manager_role = web3.keccak(text="APP_MANAGER_ROLE") + assert acl.getPermissionManager(ARAGON_KERNEL, + app_manager_role) == AGENT, "AGENT should be the permission manager for APP_MANAGER_ROLE" + assert nor.kernel() == ARAGON_KERNEL, "Node Operators Registry must use the correct kernel" + assert not acl.hasPermission(VOTING, ARAGON_KERNEL, + app_manager_role), "VOTING should not have APP_MANAGER_ROLE before the upgrade" + assert not acl.hasPermission(AGENT, ARAGON_KERNEL, + app_manager_role), "AGENT should not have APP_MANAGER_ROLE before the upgrade" + + # Steps 1.23-1.27: Check NOR and sDVT initial state + assert not acl.hasPermission(agent, kernel, + app_manager_role), "Agent should not have APP_MANAGER_ROLE before upgrade" + assert nor.getContractVersion() == 3, "Node Operators Registry version should be 3 before upgrade" + assert simple_dvt.getContractVersion() == 3, "Simple DVT version should be 3 before upgrade" + + # Step 1.28: Check CONFIG_MANAGER_ROLE initial state + config_manager_role = oracle_daemon_config.CONFIG_MANAGER_ROLE() + assert not oracle_daemon_config.hasRole(config_manager_role, + agent), "Agent should not have CONFIG_MANAGER_ROLE on Oracle Daemon Config before upgrade" + + # Steps 1.29-1.31: Check Oracle Daemon Config variables to be removed + try: + oracle_daemon_config.get('NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP') + oracle_daemon_config.get('VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS') + oracle_daemon_config.get('VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS') + except Exception as e: + assert False, f"Expected variables to exist before removal: {e}" + + # Step 1.32: Check that EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS doesn't exist yet + try: + oracle_daemon_config.get('EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS') + assert False, "EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS should not exist before vote" + except Exception: + pass # Expected to fail + + # Step 1.34: Check CSM implementation initial state + assert csm_impl_before != CSM_IMPL_V2_ADDRESS, "CSM implementation should be different before vote" + + # Step 1.35: Check CSM finalizeUpgradeV2 initial state + with reverts(): + # The function should not exist yet + csm.getInitializedVersion() + + # Step 1.36: Check CSAccounting implementation (pre-vote state) + assert cs_accounting_impl_before != CS_ACCOUNTING_IMPL_V2_ADDRESS, "CSAccounting implementation should be different before vote" + + # Step 1.37: Check CSAccounting finalizeUpgradeV2 was not called (pre-vote state) + with reverts(): + # The function should not exist yet + cs_accounting.getInitializedVersion() + + # Step 1.38: Check CSFeeOracle implementation (pre-vote state) + assert cs_fee_oracle_impl_before != CS_FEE_ORACLE_IMPL_V2_ADDRESS, "CSFeeOracle implementation should be different before vote" + + # Step 1.39: Check CSFeeOracle finalizeUpgradeV2 was not called (pre-vote state) + assert cs_fee_oracle.getContractVersion() < CS_FEE_ORACLE_V2_VERSION, f"CSFeeOracle version should be less than {CS_FEE_ORACLE_V2_VERSION} before vote" + assert cs_fee_oracle.getConsensusVersion() < 3, "CSFeeOracle consensus version should be less than 3 before vote" + + # Step 1.40: Check CSFeeDistributor implementation (pre-vote state) + assert cs_fee_distributor_impl_before != CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS, "CSFeeDistributor implementation should be different before vote" + + # Step 1.41: Check CSFeeDistributor finalizeUpgradeV2 was not called (pre-vote state) + with reverts(): + # The function should not exist yet + cs_fee_distributor.getInitializedVersion() + + # Steps 1.42-1.44: CSAccounting roles (pre-vote state) + assert cs_accounting.hasRole(cs_accounting.SET_BOND_CURVE_ROLE(), + csm.address), "CSM should have SET_BOND_CURVE_ROLE on CSAccounting before vote" + assert cs_accounting.hasRole(web3.keccak(text="RESET_BOND_CURVE_ROLE"), + csm.address), "CSM should have RESET_BOND_CURVE_ROLE on CSAccounting before vote" + assert cs_accounting.hasRole(web3.keccak(text="RESET_BOND_CURVE_ROLE"), + CSM_COMMITTEE_MS), "CSM committee should have RESET_BOND_CURVE_ROLE on CSAccounting before vote" + + # Steps 1.45-1.46: CSM roles (pre-vote state) + assert not csm.hasRole(web3.keccak(text="CREATE_NODE_OPERATOR_ROLE"), + cs_permissionless_gate.address), "Permissionless gate should not have CREATE_NODE_OPERATOR_ROLE on CSM before vote" + assert not csm.hasRole(web3.keccak(text="CREATE_NODE_OPERATOR_ROLE"), + cs_vetted_gate.address), "Vetted gate should not have CREATE_NODE_OPERATOR_ROLE on CSM before vote" + + # Step 1.47: CSAccounting bond curve role for vetted gate (pre-vote state) + assert not cs_accounting.hasRole(cs_accounting.SET_BOND_CURVE_ROLE(), + cs_vetted_gate.address), "Vetted gate should not have SET_BOND_CURVE_ROLE on CSAccounting before vote" + + # Steps 1.48-1.49: Verifier roles (pre-vote state) + assert csm.hasRole(csm.VERIFIER_ROLE(), + CS_VERIFIER_ADDRESS_OLD), "Old verifier should have VERIFIER_ROLE on CSM before vote" + assert not csm.hasRole(csm.VERIFIER_ROLE(), + cs_verifier_v2.address), "New verifier should not have VERIFIER_ROLE on CSM before vote" + + # Steps 1.50-1.55: GateSeal roles (pre-vote state) + assert csm.hasRole(csm.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should have PAUSE_ROLE on CSM before vote" + assert cs_accounting.hasRole(cs_accounting.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should have PAUSE_ROLE on CSAccounting before vote" + assert cs_fee_oracle.hasRole(cs_fee_oracle.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should have PAUSE_ROLE on CSFeeOracle before vote" + + assert not csm.hasRole(csm.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should not have PAUSE_ROLE on CSM before vote" + assert not cs_accounting.hasRole(cs_accounting.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should not have PAUSE_ROLE on CSAccounting before vote" + assert not cs_fee_oracle.hasRole(cs_fee_oracle.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should not have PAUSE_ROLE on CSFeeOracle before vote" + + # Step 1.56-1.58: No Identified Community Stakers Gate Bond Curve before vote + assert not cs_accounting.hasRole(cs_accounting.MANAGE_BOND_CURVES_ROLE(), agent.address) + with reverts(): + cs_accounting.getCurveInfo(len(CS_CURVES)) + + # Step 1.59: Staking Router CSM module state before vote (pre-vote state) + csm_module_before = staking_router.getStakingModule(CS_MODULE_ID) + csm_share_before = csm_module_before['stakeShareLimit'] + csm_priority_exit_threshold_before = csm_module_before['priorityExitShareThreshold'] + assert csm_share_before != CS_MODULE_NEW_TARGET_SHARE_BP, f"CSM share should not be {CS_MODULE_NEW_TARGET_SHARE_BP} before vote, current: {csm_share_before}" + assert csm_share_before == CS_MODULE_TARGET_SHARE_BP, f"CSM share should be {CS_MODULE_TARGET_SHARE_BP} before vote, current: {csm_share_before}" + assert csm_priority_exit_threshold_before != CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP, f"CSM priority exit threshold should not be {CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP} before vote, current: {csm_priority_exit_threshold_before}" + assert csm_priority_exit_threshold_before == CS_MODULE_PRIORITY_EXIT_SHARE_THRESHOLD, f"CSM priority exit threshold should be {CS_MODULE_PRIORITY_EXIT_THRESHOLD_BP} before vote, current: {csm_priority_exit_threshold_before}" + + assert csm_module_before['name'] == CS_MODULE_NAME, "CSM module name should not change before vote" + assert csm_module_before['stakingModuleAddress'] == CSM_ADDRESS, "CSM module address should not change before vote" + assert csm_module_before['stakingModuleFee'] == CS_MODULE_MODULE_FEE_BP, "CSM module fee should not change before vote" + assert csm_module_before['treasuryFee'] == CS_MODULE_TREASURY_FEE_BP, "CSM treasury fee should not change before vote" + assert csm_module_before['maxDepositsPerBlock'] == CS_MODULE_MAX_DEPOSITS_PER_BLOCK, "CSM max deposits per block should not change before vote" + assert csm_module_before['minDepositBlockDistance'] == CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE, "CSM min deposit block distance should not change before vote" + + # Steps 1.60-1.64: Gate Seals - Check initial states before vote + assert withdrawal_queue.hasRole(withdrawal_queue.PAUSE_ROLE(), OLD_GATE_SEAL_ADDRESS), "Old GateSeal should have PAUSE_ROLE on WithdrawalQueue before vote" + assert validators_exit_bus_oracle.hasRole(validators_exit_bus_oracle.PAUSE_ROLE(), OLD_GATE_SEAL_ADDRESS), "Old GateSeal should have PAUSE_ROLE on VEBO before vote" + assert not withdrawal_queue.hasRole(withdrawal_queue.PAUSE_ROLE(), NEW_WQ_GATE_SEAL), "New WQ GateSeal should not have PAUSE_ROLE on WithdrawalQueue before vote" + assert not validators_exit_bus_oracle.hasRole(validators_exit_bus_oracle.PAUSE_ROLE(), NEW_TW_GATE_SEAL), "New TW GateSeal should not have PAUSE_ROLE on VEBO before vote" + assert not triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.PAUSE_ROLE(), NEW_TW_GATE_SEAL), "New TW GateSeal should not have PAUSE_ROLE on TWG before vote" + + # Steps 1.65-1.66: ResealManager - Check initial states before vote + assert not triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.PAUSE_ROLE(), RESEAL_MANAGER), "ResealManager should not have PAUSE_ROLE on TWG before vote" + assert not triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.RESUME_ROLE(), RESEAL_MANAGER), "ResealManager should not have RESUME_ROLE on TWG before vote" + # Steps 1.67-1.68: Rename Nethermind NO and change reward address + nethermind_no_data_before = no_registry.getNodeOperator(NETHERMIND_NO_ID, True) + + assert nethermind_no_data_before["rewardAddress"] == NETHERMIND_NO_STAKING_REWARDS_ADDRESS_OLD + assert nethermind_no_data_before["name"] == NETHERMIND_NO_NAME_OLD + + # Steps 1.69-1.70: Check DSM guardians initial state + assert dsm.isGuardian(OLD_KILN_ADDRESS), "Old Kiln address should be in guardians before vote" + assert not dsm.isGuardian(NEW_KILN_ADDRESS), "New Kiln address should not be in guardians before vote" + + # Step 1.71: Time constraints will be enforced during execution + + if details["status"] == PROPOSAL_STATUS["submitted"]: + chain.sleep(timelock.getAfterSubmitDelay() + 1) + dual_governance.scheduleProposal(EXPECTED_DG_PROPOSAL_ID, {"from": stranger}) + + if timelock.getProposalDetails(EXPECTED_DG_PROPOSAL_ID)["status"] == PROPOSAL_STATUS["scheduled"]: + chain.sleep(timelock.getAfterScheduleDelay() + 1) + # Wait for time window (13:00-19:00 UTC) to satisfy time constraints + wait_for_time_window(13, 19) + + dg_tx: TransactionReceipt = timelock.execute(EXPECTED_DG_PROPOSAL_ID, {"from": stranger}) + display_dg_events(dg_tx) + dg_events = group_dg_events_from_receipt( + dg_tx, + timelock=EMERGENCY_PROTECTED_TIMELOCK, + admin_executor=DUAL_GOVERNANCE_ADMIN_EXECUTOR, + ) + assert count_vote_items_by_events(dg_tx, AGENT) == EXPECTED_DG_EVENTS_FROM_AGENT + assert len(dg_events) == EXPECTED_DG_EVENTS_COUNT + + # === DG EXECUTION EVENTS VALIDATION === + # 0. Lido Locator upgrade events + validate_proxy_upgrade_event(dg_events[0], LIDO_LOCATOR_IMPL, emitted_by=lido_locator_proxy) + + # 1. VEBO upgrade events + validate_proxy_upgrade_event(dg_events[1], VALIDATORS_EXIT_BUS_ORACLE_IMPL, emitted_by=vebo_proxy) + + # 2. VEBO finalize upgrade events + validate_contract_version_set_event(dg_events[2], version=2, emitted_by=validators_exit_bus_oracle, + events_chain=["LogScriptCall", "ContractVersionSet", "SetMaxValidatorsPerReport", "ExitRequestsLimitSet", "ScriptResult", "Executed"]) + assert 'ExitRequestsLimitSet' in dg_events[2], "ExitRequestsLimitSet event not found" + assert dg_events[2]['ExitRequestsLimitSet'][0]['maxExitRequestsLimit'] == MAX_EXIT_REQUESTS_LIMIT, "Wrong maxExitRequestsLimit" + assert dg_events[2]['ExitRequestsLimitSet'][0]['exitsPerFrame'] == EXITS_PER_FRAME, "Wrong exitsPerFrame" + assert dg_events[2]['ExitRequestsLimitSet'][0]['frameDurationInSec'] == FRAME_DURATION_IN_SEC, "Wrong frameDurationInSec" + + # 3. Grant VEBO MANAGE_CONSENSUS_VERSION_ROLE to Agent + validate_role_grant_event( + dg_events[3], + role_hash=web3.keccak(text="MANAGE_CONSENSUS_VERSION_ROLE").hex(), + account=agent.address, + emitted_by=validators_exit_bus_oracle + ) + + # 4. Set VEBO consensus version to 4 + validate_consensus_version_set_event( + dg_events[4], + new_version=4, + prev_version=3, + emitted_by=validators_exit_bus_oracle + ) + + # 5. Revoke VEBO MANAGE_CONSENSUS_VERSION_ROLE from Agent + validate_role_revoke_event( + dg_events[5], + role_hash=web3.keccak(text="MANAGE_CONSENSUS_VERSION_ROLE").hex(), + account=agent.address, + emitted_by=validators_exit_bus_oracle + ) + + # 6. Grant VEBO SUBMIT_REPORT_HASH_ROLE to EasyTrack executor + validate_role_grant_event( + dg_events[6], + role_hash=web3.keccak(text="SUBMIT_REPORT_HASH_ROLE").hex(), + account=EASYTRACK_EVMSCRIPT_EXECUTOR, + emitted_by=validators_exit_bus_oracle + ) + + # 7. Grant TWG ADD_FULL_WITHDRAWAL_REQUEST_ROLE to CS Ejector + validate_role_grant_event( + dg_events[7], + role_hash=web3.keccak(text="ADD_FULL_WITHDRAWAL_REQUEST_ROLE").hex(), + account=CS_EJECTOR_ADDRESS, + emitted_by=triggerable_withdrawals_gateway + ) + + # 8. Grant TWG ADD_FULL_WITHDRAWAL_REQUEST_ROLE to VEBO + validate_role_grant_event( + dg_events[8], + role_hash=web3.keccak(text="ADD_FULL_WITHDRAWAL_REQUEST_ROLE").hex(), + account=validators_exit_bus_oracle.address, + emitted_by=triggerable_withdrawals_gateway + ) + + # 9. Connect TWG to Dual Governance tiebreaker + assert 'SealableWithdrawalBlockerAdded' in dg_events[9], "SealableWithdrawalBlockerAdded event not found" + assert dg_events[9]['SealableWithdrawalBlockerAdded'][0]['sealable'] == TRIGGERABLE_WITHDRAWALS_GATEWAY, "Wrong sealableWithdrawalBlocker" + + # 10. Update WithdrawalVault implementation + validate_proxy_upgrade_event(dg_events[10], WITHDRAWAL_VAULT_IMPL, emitted_by=withdrawal_vault) + + # 11. Call finalizeUpgrade_v2 on WithdrawalVault + validate_contract_version_set_event(dg_events[11], version=2, emitted_by=withdrawal_vault) + + # 12. Update AO implementation + validate_proxy_upgrade_event(dg_events[12], ACCOUNTING_ORACLE_IMPL, emitted_by=accounting_oracle) + + # 13. Grant AO MANAGE_CONSENSUS_VERSION_ROLE to the AGENT + validate_role_grant_event( + dg_events[13], + role_hash=web3.keccak(text="MANAGE_CONSENSUS_VERSION_ROLE").hex(), + account=agent.address, + emitted_by=accounting_oracle + ) + + # 14. Bump AO consensus version to 4 + validate_consensus_version_set_event( + dg_events[14], + new_version=4, + prev_version=3, + emitted_by=accounting_oracle + ) + + # 15. Revoke AO MANAGE_CONSENSUS_VERSION_ROLE from the AGENT + validate_role_revoke_event( + dg_events[15], + role_hash=web3.keccak(text="MANAGE_CONSENSUS_VERSION_ROLE").hex(), + account=agent.address, + emitted_by=accounting_oracle + ) + + # 16. Call finalizeUpgrade_v3() on AO + validate_contract_version_set_event(dg_events[16], version=3, emitted_by=accounting_oracle) + + # 17. Update SR implementation + validate_proxy_upgrade_event(dg_events[17], STAKING_ROUTER_IMPL, emitted_by=staking_router) + + # 18. Call finalizeUpgrade_v3() on SR + validate_contract_version_set_event(dg_events[18], version=3, emitted_by=staking_router) + + # 19. Grant SR REPORT_VALIDATOR_EXITING_STATUS_ROLE to ValidatorExitVerifier + validate_role_grant_event( + dg_events[19], + role_hash=web3.keccak(text="REPORT_VALIDATOR_EXITING_STATUS_ROLE").hex(), + account=VALIDATOR_EXIT_VERIFIER, + emitted_by=staking_router + ) + + # 20. Grant SR REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE to TWG + validate_role_grant_event( + dg_events[20], + role_hash=web3.keccak(text="REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE").hex(), + account=triggerable_withdrawals_gateway.address, + emitted_by=staking_router + ) + + # 21. Grant APP_MANAGER_ROLE on Kernel to Voting + assert 'SetPermission' in dg_events[21] + assert dg_events[21]['SetPermission'][0]['allowed'] is True + + # 22. Set new implementation for NOR + assert 'SetApp' in dg_events[22] + + # 23. Finalize upgrade for NOR + validate_contract_version_set_event(dg_events[23], version=4, emitted_by=nor, + events_chain=["LogScriptCall", "Approval", "ContractVersionSet", "ExitDeadlineThresholdChanged", "ScriptResult", "Executed"]) + assert 'ExitDeadlineThresholdChanged' in dg_events[23] + assert dg_events[23]['ExitDeadlineThresholdChanged'][0]['threshold'] == NOR_EXIT_DEADLINE_IN_SEC + + # 24. Set new implementation for sDVT + assert 'SetApp' in dg_events[24] + + # 25. Finalize upgrade for sDVT + validate_contract_version_set_event(dg_events[25], version=4, emitted_by=simple_dvt, + events_chain=["LogScriptCall", "Approval", "ContractVersionSet", "ExitDeadlineThresholdChanged", "ScriptResult", "Executed"]) + assert 'ExitDeadlineThresholdChanged' in dg_events[25] + assert dg_events[25]['ExitDeadlineThresholdChanged'][0]['threshold'] == NOR_EXIT_DEADLINE_IN_SEC + + # 26. Revoke APP_MANAGER_ROLE on Kernel from Voting + assert 'SetPermission' in dg_events[26] + assert dg_events[26]['SetPermission'][0]['allowed'] is False + + # 27. Grant CONFIG_MANAGER_ROLE on OracleDaemonConfig to Agent + validate_role_grant_event( + dg_events[27], + role_hash=oracle_daemon_config.CONFIG_MANAGER_ROLE().hex(), + account=agent.address, + emitted_by=oracle_daemon_config + ) + + # 28. Unset NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP + assert 'ConfigValueUnset' in dg_events[28] + assert 'NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP' in dg_events[28]['ConfigValueUnset'][0]['key'] + + # 29. Unset VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS + assert 'ConfigValueUnset' in dg_events[29] + assert 'VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS' in dg_events[29]['ConfigValueUnset'][0]['key'] + + # 30. Unset VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS + assert 'ConfigValueUnset' in dg_events[30] + assert 'VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS' in dg_events[30]['ConfigValueUnset'][0]['key'] + + # 31. Set EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS + assert 'ConfigValueSet' in dg_events[31] + assert 'EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS' in dg_events[31]['ConfigValueSet'][0]['key'] + assert convert.to_int(dg_events[31]['ConfigValueSet'][0]['value']) == EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS + + # 32. Revoke CONFIG_MANAGER_ROLE from the AGENT + validate_role_revoke_event( + dg_events[32], + role_hash=oracle_daemon_config.CONFIG_MANAGER_ROLE().hex(), + account=agent.address, + emitted_by=oracle_daemon_config + ) + + # 33. CSM implementation upgrade + validate_proxy_upgrade_event(dg_events[33], CSM_IMPL_V2_ADDRESS, emitted_by=csm) + + # 34. CSM finalize upgrade validation + assert 'Initialized' in dg_events[34] + assert dg_events[34]['Initialized'][0]['version'] == CSM_V2_VERSION + + # 35. CSAccounting implementation upgrade + validate_proxy_upgrade_event(dg_events[35], CS_ACCOUNTING_IMPL_V2_ADDRESS, + emitted_by=cs_accounting) + + # 36. CSAccounting finalize upgrade with bond curves + assert 'BondCurveAdded' in dg_events[36] + assert len(dg_events[36]['BondCurveAdded']) == len(CS_CURVES) + validate_bond_curve_added_on_init_v2_events(dg_events[36], CS_CURVES, emitted_by=cs_accounting) + assert 'Initialized' in dg_events[36] + assert dg_events[36]['Initialized'][0]['version'] == CS_ACCOUNTING_V2_VERSION + + # 37. CSFeeOracle implementation upgrade + validate_proxy_upgrade_event(dg_events[37], CS_FEE_ORACLE_IMPL_V2_ADDRESS, + emitted_by=cs_fee_oracle) + + # 38. CSFeeOracle finalize upgrade with consensus version + validate_consensus_version_set_event(dg_events[38], new_version=CSM_CONSENSUS_NEW_VERSION, prev_version=CSM_CONSENSUS_OLD_VERSION, + emitted_by=cs_fee_oracle, + events_chain=["LogScriptCall", "ConsensusVersionSet", "ContractVersionSet", "ScriptResult", "Executed"]) + validate_contract_version_set_event(dg_events[38], version=CS_FEE_ORACLE_V2_VERSION, + emitted_by=cs_fee_oracle, + events_chain=["LogScriptCall", "ConsensusVersionSet", "ContractVersionSet", "ScriptResult", "Executed"]) + + # 39. CSFeeDistributor implementation upgrade + validate_proxy_upgrade_event(dg_events[39], CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS, + emitted_by=cs_fee_distributor) + + # 40. CSFeeDistributor finalize upgrade + assert 'RebateRecipientSet' in dg_events[40] + assert dg_events[40]['RebateRecipientSet'][0]['recipient'] == agent.address + assert 'Initialized' in dg_events[40] + assert dg_events[40]['Initialized'][0]['version'] == CS_FEE_DISTRIBUTOR_V2_VERSION + + # 41. Revoke SET_BOND_CURVE_ROLE from CSM on CSAccounting + validate_role_revoke_event( + dg_events[41], + role_hash=cs_accounting.SET_BOND_CURVE_ROLE().hex(), + account=csm.address, + emitted_by=cs_accounting + ) + + # 42. Revoke RESET_BOND_CURVE_ROLE from CSM on CSAccounting + validate_role_revoke_event( + dg_events[42], + role_hash=web3.keccak(text="RESET_BOND_CURVE_ROLE").hex(), + account=csm.address, + emitted_by=cs_accounting + ) + + # 43. Revoke RESET_BOND_CURVE_ROLE from CSM committee on CSAccounting + validate_role_revoke_event( + dg_events[43], + role_hash=web3.keccak(text="RESET_BOND_CURVE_ROLE").hex(), + account=CSM_COMMITTEE_MS, + emitted_by=cs_accounting + ) + + # 44. Grant CREATE_NODE_OPERATOR_ROLE to permissionless gate on CSM + validate_role_grant_event( + dg_events[44], + role_hash=csm.CREATE_NODE_OPERATOR_ROLE().hex(), + account=CS_PERMISSIONLESS_GATE_ADDRESS, + emitted_by=csm + ) + + # 45. Grant CREATE_NODE_OPERATOR_ROLE to vetted gate on CSM + validate_role_grant_event( + dg_events[45], + role_hash=csm.CREATE_NODE_OPERATOR_ROLE().hex(), + account=CS_VETTED_GATE_ADDRESS, + emitted_by=csm + ) + + # 46. Grant SET_BOND_CURVE_ROLE to vetted gate on CSAccounting + validate_role_grant_event( + dg_events[46], + role_hash=cs_accounting.SET_BOND_CURVE_ROLE().hex(), + account=CS_VETTED_GATE_ADDRESS, + emitted_by=cs_accounting + ) + + # 47. Revoke VERIFIER_ROLE from old verifier on CSM + validate_role_revoke_event( + dg_events[47], + role_hash=csm.VERIFIER_ROLE().hex(), + account=CS_VERIFIER_ADDRESS_OLD, + emitted_by=csm + ) + + # 48. Grant VERIFIER_ROLE to new verifier on CSM + validate_role_grant_event( + dg_events[48], + role_hash=csm.VERIFIER_ROLE().hex(), + account=CS_VERIFIER_V2_ADDRESS, + emitted_by=csm + ) + + # 49. Revoke PAUSE_ROLE from old GateSeal on CSM + validate_role_revoke_event( + dg_events[49], + role_hash=csm.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_ADDRESS, + emitted_by=csm + ) + + # 50. Revoke PAUSE_ROLE from old GateSeal on CSAccounting + validate_role_revoke_event( + dg_events[50], + role_hash=cs_accounting.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_ADDRESS, + emitted_by=cs_accounting + ) + + # 51. Revoke PAUSE_ROLE from old GateSeal on CSFeeOracle + validate_role_revoke_event( + dg_events[51], + role_hash=cs_fee_oracle.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_ADDRESS, + emitted_by=cs_fee_oracle + ) + + # 52. Grant PAUSE_ROLE to new GateSeal on CSM + validate_role_grant_event( + dg_events[52], + role_hash=csm.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_V2_ADDRESS, + emitted_by=csm + ) + + # 53. Grant PAUSE_ROLE to new GateSeal on CSAccounting + validate_role_grant_event( + dg_events[53], + role_hash=cs_accounting.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_V2_ADDRESS, + emitted_by=cs_accounting + ) + + # 54. Grant PAUSE_ROLE to new GateSeal on CSFeeOracle + validate_role_grant_event( + dg_events[54], + role_hash=cs_fee_oracle.PAUSE_ROLE().hex(), + account=CS_GATE_SEAL_V2_ADDRESS, + emitted_by=cs_fee_oracle + ) + + # 55. Grant MANAGE_BOND_CURVES_ROLE to agent on CSAccounting + validate_role_grant_event( + dg_events[55], + role_hash=cs_accounting.MANAGE_BOND_CURVES_ROLE().hex(), + account=agent.address, + emitted_by=cs_accounting + ) + + # 56. Add ICS bond curve + ics_curve_id = len(CS_CURVES) + validate_bond_curve_added_event(dg_events[56], curve_id=ics_curve_id, curve_intervals=CS_ICS_GATE_BOND_CURVE, emitted_by=cs_accounting) + + # 57. Revoke MANAGE_BOND_CURVES_ROLE from agent on CSAccounting + validate_role_revoke_event( + dg_events[57], + role_hash=cs_accounting.MANAGE_BOND_CURVES_ROLE().hex(), + account=agent.address, + emitted_by=cs_accounting + ) + + # 58. Increase CSM share in Staking Router + validate_staking_module_update_event( + dg_events[58], + module_id=CS_MODULE_ID, + share_limit=CS_MODULE_NEW_TARGET_SHARE_BP, + priority_share_threshold=CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP, + module_fee_points_bp=CS_MODULE_MODULE_FEE_BP, + treasury_fee_points_bp=CS_MODULE_TREASURY_FEE_BP, + max_deposits_per_block=CS_MODULE_MAX_DEPOSITS_PER_BLOCK, + min_deposit_block_distance=CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE, + emitted_by=staking_router + ) + + # 59-65. Gate Seals and ResealManager role updates + # 59. Revoke PAUSE_ROLE on WithdrawalQueue from the old GateSeal + validate_role_revoke_event( + dg_events[59], + role_hash=withdrawal_queue.PAUSE_ROLE().hex(), + account=OLD_GATE_SEAL_ADDRESS, + emitted_by=withdrawal_queue + ) + + # 60. Revoke PAUSE_ROLE on ValidatorsExitBusOracle from the old GateSeal + validate_role_revoke_event( + dg_events[60], + role_hash=validators_exit_bus_oracle.PAUSE_ROLE().hex(), + account=OLD_GATE_SEAL_ADDRESS, + emitted_by=validators_exit_bus_oracle + ) + + # 61. Grant PAUSE_ROLE on WithdrawalQueue to the new WithdrawalQueue GateSeal + validate_role_grant_event( + dg_events[61], + role_hash=withdrawal_queue.PAUSE_ROLE().hex(), + account=NEW_WQ_GATE_SEAL, + emitted_by=withdrawal_queue + ) + + # 62. Grant PAUSE_ROLE on ValidatorsExitBusOracle to the new Triggerable Withdrawals GateSeal + validate_role_grant_event( + dg_events[62], + role_hash=validators_exit_bus_oracle.PAUSE_ROLE().hex(), + account=NEW_TW_GATE_SEAL, + emitted_by=validators_exit_bus_oracle + ) + + # 63. Grant PAUSE_ROLE on TriggerableWithdrawalsGateway to the new Triggerable Withdrawals GateSeal + validate_role_grant_event( + dg_events[63], + role_hash=triggerable_withdrawals_gateway.PAUSE_ROLE().hex(), + account=NEW_TW_GATE_SEAL, + emitted_by=triggerable_withdrawals_gateway + ) + + # 64. Grant PAUSE_ROLE on TriggerableWithdrawalsGateway to ResealManager + validate_role_grant_event( + dg_events[64], + role_hash=triggerable_withdrawals_gateway.PAUSE_ROLE().hex(), + account=RESEAL_MANAGER, + emitted_by=triggerable_withdrawals_gateway + ) + + # 65. Grant RESUME_ROLE on TriggerableWithdrawalsGateway to ResealManager + validate_role_grant_event( + dg_events[65], + role_hash=triggerable_withdrawals_gateway.RESUME_ROLE().hex(), + account=RESEAL_MANAGER, + emitted_by=triggerable_withdrawals_gateway + ) + + # 66. Validate Nethermind NO name change + validate_node_operator_name_set_event( + dg_events[66], + NodeOperatorNameSetItem(nodeOperatorId=NETHERMIND_NO_ID, name=NETHERMIND_NO_NAME_NEW), + emitted_by=no_registry, + is_dg_event=True, + ) + + # 67. Validate Nethermind NO rewards address change + validate_node_operator_reward_address_set_event( + dg_events[67], + NodeOperatorRewardAddressSetItem( + nodeOperatorId=NETHERMIND_NO_ID, reward_address=NETHERMIND_NO_STAKING_REWARDS_ADDRESS_NEW + ), + emitted_by=no_registry, + is_dg_event=True, + ) + # 68. Guardian remove event + validate_remove_guardian_event( + dg_events[68], + OLD_KILN_ADDRESS, + emitted_by=dsm.address, + ) + # 69. Guardian add event + validate_add_guardian_event( + dg_events[69], + NEW_KILN_ADDRESS, + emitted_by=dsm.address, + ) + + # 70. Time constraints event validation + assert 'TimeWithinDayTimeChecked' in dg_events[70], "TimeWithinDayTimeChecked event not found" + assert dg_events[70]['TimeWithinDayTimeChecked'][0]['startDayTime'] == UTC13, "Wrong startDayTime for time constraints (expected 13:00 UTC)" + assert dg_events[70]['TimeWithinDayTimeChecked'][0]['endDayTime'] == UTC19, "Wrong endDayTime for time constraints (expected 19:00 UTC)" + assert convert.to_address( + dg_events[70]['TimeWithinDayTimeChecked'][0]['_emitted_by']) == convert.to_address( + DUAL_GOVERNANCE_TIME_CONSTRAINTS), "Wrong event emitter for time constraints" + + # Step 1.1: Validate Lido Locator implementation was updated + assert get_ossifiable_proxy_impl(lido_locator_proxy) == LIDO_LOCATOR_IMPL, "Locator implementation should be updated to the new value" + + # Step 1.2-1.3: Validate VEBO implementation was updated and configured + assert get_ossifiable_proxy_impl(vebo_proxy) == VALIDATORS_EXIT_BUS_ORACLE_IMPL, "VEBO implementation should be updated" + assert validators_exit_bus_oracle.getMaxValidatorsPerReport() == 600, "VEBO max validators per report should be set to 600" + + # Validate exit request limit parameters from finalizeUpgrade_v2 call + exit_request_limits = validators_exit_bus_oracle.getExitRequestLimitFullInfo() + assert exit_request_limits[0] == MAX_EXIT_REQUESTS_LIMIT, "maxExitRequestsLimit should be 11200" + assert exit_request_limits[1] == EXITS_PER_FRAME, "exitsPerFrame should be 1" + assert exit_request_limits[2] == FRAME_DURATION_IN_SEC, "frameDurationInSec should be 48 in seconds" + + # Steps 1.4-1.6: Validate VEBO consensus version management + assert not validators_exit_bus_oracle.hasRole( + validators_exit_bus_oracle.MANAGE_CONSENSUS_VERSION_ROLE(), + agent), "Agent should not have MANAGE_CONSENSUS_VERSION_ROLE on VEBO" + assert validators_exit_bus_oracle.getConsensusVersion() == VEBO_CONSENSUS_VERSION, f"VEBO consensus version should be set to {VEBO_CONSENSUS_VERSION}" + + # Step 1.7: Validate EasyTrack VEB SUBMIT_REPORT_HASH_ROLE + assert validators_exit_bus_oracle.hasRole(submit_report_hash_role,EASYTRACK_EVMSCRIPT_EXECUTOR), "EasyTrack executor should have SUBMIT_REPORT_HASH_ROLE on VEBO" + + # Steps 1.8-1.9: Validate TWG roles + assert triggerable_withdrawals_gateway.hasRole(add_full_withdrawal_request_role, cs_ejector), "CS Ejector should have ADD_FULL_WITHDRAWAL_REQUEST_ROLE on TWG" + assert triggerable_withdrawals_gateway.hasRole(add_full_withdrawal_request_role, validators_exit_bus_oracle), "VEBO should have ADD_FULL_WITHDRAWAL_REQUEST_ROLE on TWG" + + # Step 1.10: Validate DualGovernance tiebreaker connection + final_tiebreaker_details = dual_governance.getTiebreakerDetails() + final_tiebreakers = final_tiebreaker_details[3] # sealableWithdrawalBlockers + assert TRIGGERABLE_WITHDRAWALS_GATEWAY in final_tiebreakers, "TWG should be in tiebreaker list after upgrade" + + # Steps 1.11-1.12: Validate Withdrawal Vault upgrade + assert get_wv_contract_proxy_impl(withdrawal_vault) == WITHDRAWAL_VAULT_IMPL, "Withdrawal Vault implementation should be updated" + assert withdrawal_vault.getContractVersion() == 2, "Withdrawal Vault version should be 2 after finalizeUpgrade_v2" + + # Steps 1.13-1.16: Validate Accounting Oracle upgrade + assert get_ossifiable_proxy_impl(accounting_oracle) == ACCOUNTING_ORACLE_IMPL, "Accounting Oracle implementation should be updated" + assert not accounting_oracle.hasRole(accounting_oracle.MANAGE_CONSENSUS_VERSION_ROLE(), agent), "Agent should not have MANAGE_CONSENSUS_VERSION_ROLE on AO" + assert accounting_oracle.getConsensusVersion() == AO_CONSENSUS_VERSION, f"AO consensus version should be set to {AO_CONSENSUS_VERSION}" + + # Step 1.17: Validate AO finalizeUpgrade_v3 + assert accounting_oracle.getContractVersion() == 3, "AO contract version should be 3 after finalizeUpgrade_v3" + + # Steps 1.18-1.21: Validate Staking Router upgrade + assert get_ossifiable_proxy_impl(staking_router) == STAKING_ROUTER_IMPL, "Staking Router implementation should be updated" + assert staking_router.getContractVersion() == 3, "Staking Router version should be 3 after finalizeUpgrade_v3" + assert staking_router.hasRole(staking_router.REPORT_VALIDATOR_EXITING_STATUS_ROLE(), VALIDATOR_EXIT_VERIFIER), "ValidatorExitVerifier should have REPORT_VALIDATOR_EXITING_STATUS_ROLE on SR" + assert staking_router.hasRole(staking_router.REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE(), triggerable_withdrawals_gateway), "TWG should have REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE on SR" + + # Steps 1.22-1.27: Validate NOR and sDVT updates + assert not acl.hasPermission(agent, kernel, app_manager_role), "Agent should not have APP_MANAGER_ROLE after vote" + assert nor.getContractVersion() == 4, "Node Operators Registry version should be updated to 4" + assert simple_dvt.getContractVersion() == 4, "Simple DVT version should be updated to 4" + assert nor.exitDeadlineThreshold(0) == NOR_EXIT_DEADLINE_IN_SEC, "NOR exit deadline threshold should be set correctly after finalizeUpgrade_v4" + assert simple_dvt.exitDeadlineThreshold(0) == NOR_EXIT_DEADLINE_IN_SEC, "sDVT exit deadline threshold should be set correctly after finalizeUpgrade_v4" + + # Steps 1.28-1.33: Validate Oracle Daemon Config changes + assert not oracle_daemon_config.hasRole(config_manager_role, agent), "Agent should not have CONFIG_MANAGER_ROLE on Oracle Daemon Config" + for var_name in ['NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP', 'VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS', + 'VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS']: + try: + oracle_daemon_config.get(var_name) + except VirtualMachineError: + pass # Expected to fail - variable should be removed + else: + raise AssertionError(f"Variable {var_name} should have been removed") + assert convert.to_uint(oracle_daemon_config.get( + 'EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS')) == EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS, f"EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS should be set to {EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS}" + + # Step 1.34: Validate CSM implementation upgrade + check_proxy_implementation(csm.address, CSM_IMPL_V2_ADDRESS) + + # Step 1.35: Validate CSM finalizeUpgradeV2 was called + assert csm.getInitializedVersion() == CSM_V2_VERSION, f"CSM version should be {CSM_V2_VERSION} after vote" + + # Step 1.36: Validate CSAccounting implementation upgrade + check_proxy_implementation(cs_accounting.address, CS_ACCOUNTING_IMPL_V2_ADDRESS) + + # Step 1.37: Validate CSAccounting finalizeUpgradeV2 was called with bond curves + assert cs_accounting.getInitializedVersion() == CS_ACCOUNTING_V2_VERSION, f"CSAccounting version should be {CS_ACCOUNTING_V2_VERSION} after vote" + for curve_id in range(len(CS_CURVES)): + curve = cs_accounting.getCurveInfo(curve_id)[0] + validate_added_bond_curve(curve, CS_CURVES[curve_id]) + + # Step 1.38: Validate CSFeeOracle implementation upgrade + check_proxy_implementation(cs_fee_oracle.address, CS_FEE_ORACLE_IMPL_V2_ADDRESS) + + # Step 1.39: Validate CSFeeOracle finalizeUpgradeV2 was called with consensus version 3 + assert cs_fee_oracle.getContractVersion() == CS_FEE_ORACLE_V2_VERSION, f"CSFeeOracle version should be {CS_FEE_ORACLE_V2_VERSION} after vote" + assert cs_fee_oracle.getConsensusVersion() == CSM_CONSENSUS_NEW_VERSION, "CSFeeOracle consensus version should be 3 after vote" + + # Step 1.40: Validate CSFeeDistributor implementation upgrade + check_proxy_implementation(cs_fee_distributor.address, CS_FEE_DISTRIBUTOR_IMPL_V2_ADDRESS) + + # Step 1.41: Validate CSFeeDistributor finalizeUpgradeV2 was called + assert cs_fee_distributor.getInitializedVersion() == CS_FEE_DISTRIBUTOR_V2_VERSION, f"CSFeeDistributor version should be {CS_FEE_DISTRIBUTOR_V2_VERSION} after vote" + assert cs_fee_distributor.rebateRecipient() == agent.address, "Rebate recipient should be the agent after vote" + + # Step 1.42: Validate SET_BOND_CURVE_ROLE was revoked from CSM on CSAccounting + assert not cs_accounting.hasRole(cs_accounting.SET_BOND_CURVE_ROLE(), + csm.address), "CSM should not have SET_BOND_CURVE_ROLE on CSAccounting after vote" + + # Step 1.43: Validate RESET_BOND_CURVE_ROLE was revoked from CSM on CSAccounting + assert not cs_accounting.hasRole(web3.keccak(text="RESET_BOND_CURVE_ROLE"), + csm.address), "CSM should not have RESET_BOND_CURVE_ROLE on CSAccounting after vote" + + # Step 1.44: Validate RESET_BOND_CURVE_ROLE was revoked from CSM committee on CSAccounting + assert not cs_accounting.hasRole(web3.keccak(text="RESET_BOND_CURVE_ROLE"), + CSM_COMMITTEE_MS), "CSM committee should not have RESET_BOND_CURVE_ROLE on CSAccounting after vote" + + # Step 1.45: Validate CREATE_NODE_OPERATOR_ROLE was granted to permissionless gate on CSM + assert csm.hasRole(csm.CREATE_NODE_OPERATOR_ROLE(), + cs_permissionless_gate.address), "Permissionless gate should have CREATE_NODE_OPERATOR_ROLE on CSM after vote" + + # Step 1.46: Validate CREATE_NODE_OPERATOR_ROLE was granted to vetted gate on CSM + assert csm.hasRole(csm.CREATE_NODE_OPERATOR_ROLE(), + cs_vetted_gate.address), "Vetted gate should have CREATE_NODE_OPERATOR_ROLE on CSM after vote" + + # Step 1.47: Validate SET_BOND_CURVE_ROLE was granted to vetted gate on CSAccounting + assert cs_accounting.hasRole(cs_accounting.SET_BOND_CURVE_ROLE(), + cs_vetted_gate.address), "Vetted gate should have SET_BOND_CURVE_ROLE on CSAccounting after vote" + + # Step 1.48: Validate VERIFIER_ROLE was revoked from old verifier on CSM + assert not csm.hasRole(csm.VERIFIER_ROLE(), + CS_VERIFIER_ADDRESS_OLD), "Old verifier should not have VERIFIER_ROLE on CSM after vote" + + # Step 1.49: Validate VERIFIER_ROLE was granted to new verifier on CSM + assert csm.hasRole(csm.VERIFIER_ROLE(), + cs_verifier_v2.address), "New verifier should have VERIFIER_ROLE on CSM after vote" + + # Step 1.50: Validate PAUSE_ROLE was revoked from old GateSeal on CSM + assert not csm.hasRole(csm.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should not have PAUSE_ROLE on CSM after vote" + + # Step 1.51: Validate PAUSE_ROLE was revoked from old GateSeal on CSAccounting + assert not cs_accounting.hasRole(cs_accounting.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should not have PAUSE_ROLE on CSAccounting after vote" + + # Step 1.52: Validate PAUSE_ROLE was revoked from old GateSeal on CSFeeOracle + assert not cs_fee_oracle.hasRole(cs_fee_oracle.PAUSE_ROLE(), + CS_GATE_SEAL_ADDRESS), "Old GateSeal should not have PAUSE_ROLE on CSFeeOracle after vote" + + # Step 1.53: Validate PAUSE_ROLE was granted to new GateSeal on CSM + assert csm.hasRole(csm.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should have PAUSE_ROLE on CSM after vote" + + # Step 1.54: Validate PAUSE_ROLE was granted to new GateSeal on CSAccounting + assert cs_accounting.hasRole(cs_accounting.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should have PAUSE_ROLE on CSAccounting after vote" + + # Step 1.55: Validate PAUSE_ROLE was granted to new GateSeal on CSFeeOracle + assert cs_fee_oracle.hasRole(cs_fee_oracle.PAUSE_ROLE(), + CS_GATE_SEAL_V2_ADDRESS), "New GateSeal should have PAUSE_ROLE on CSFeeOracle after vote" + + # Step 1.56-1.58: Check add ICS Bond Curve to CSAccounting + assert not cs_accounting.hasRole(cs_accounting.MANAGE_BOND_CURVES_ROLE(), + agent), "Agent should not have MANAGE_BOND_CURVES_ROLE on CSAccounting after vote" + assert cs_accounting.getCurvesCount() == len( + CS_CURVES) + 1, "CSAccounting should have legacy bond curves and ICS Bond Curve after vote" + ics_curve = cs_accounting.getCurveInfo(ics_curve_id)[0] + validate_added_bond_curve(ics_curve, CS_ICS_GATE_BOND_CURVE) + + # Step 1.59: Increase CSM share in Staking Router + csm_module_after = staking_router.getStakingModule(CS_MODULE_ID) + csm_share_after = csm_module_after['stakeShareLimit'] + assert csm_share_after == CS_MODULE_NEW_TARGET_SHARE_BP, f"CSM share should be {CS_MODULE_NEW_TARGET_SHARE_BP} after vote, but got {csm_share_after}" + + csm_priority_exit_threshold_after = csm_module_after['priorityExitShareThreshold'] + assert csm_priority_exit_threshold_after == CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP, f"CSM priority exit threshold should be {CS_MODULE_NEW_PRIORITY_EXIT_THRESHOLD_BP} after vote, but got {csm_priority_exit_threshold_after}" + + assert csm_module_after['stakingModuleAddress'] == csm_module_before['stakingModuleAddress'] + assert csm_module_after['stakingModuleFee'] == csm_module_before['stakingModuleFee'] + assert csm_module_after['treasuryFee'] == csm_module_before['treasuryFee'] + assert csm_module_after['status'] == csm_module_before['status'] + assert csm_module_after['name'] == csm_module_before['name'] + assert csm_module_after['lastDepositAt'] == csm_module_before['lastDepositAt'] + assert csm_module_after['lastDepositBlock'] == csm_module_before['lastDepositBlock'] + assert csm_module_after['exitedValidatorsCount'] == csm_module_before['exitedValidatorsCount'] + assert csm_module_after['maxDepositsPerBlock'] == csm_module_before['maxDepositsPerBlock'] + assert csm_module_after['minDepositBlockDistance'] == csm_module_before['minDepositBlockDistance'] + + # Steps 1.60-1.64: Validate Gate Seals updates + assert not withdrawal_queue.hasRole(withdrawal_queue.PAUSE_ROLE(), OLD_GATE_SEAL_ADDRESS), "Old GateSeal should not have PAUSE_ROLE on WithdrawalQueue after vote" + assert not validators_exit_bus_oracle.hasRole(validators_exit_bus_oracle.PAUSE_ROLE(), OLD_GATE_SEAL_ADDRESS), "Old GateSeal should not have PAUSE_ROLE on VEBO after vote" + assert withdrawal_queue.hasRole(withdrawal_queue.PAUSE_ROLE(), NEW_WQ_GATE_SEAL), "New WQ GateSeal should have PAUSE_ROLE on WithdrawalQueue after vote" + assert validators_exit_bus_oracle.hasRole(validators_exit_bus_oracle.PAUSE_ROLE(),NEW_TW_GATE_SEAL), "New TW GateSeal should have PAUSE_ROLE on VEBO after vote" + assert triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.PAUSE_ROLE(), NEW_TW_GATE_SEAL), "New TW GateSeal should have PAUSE_ROLE on TWG after vote" + + # Steps 1.65-1.66: Validate ResealManager roles + assert triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.PAUSE_ROLE(), + RESEAL_MANAGER), "ResealManager should have PAUSE_ROLE on TWG after vote" + assert triggerable_withdrawals_gateway.hasRole(triggerable_withdrawals_gateway.RESUME_ROLE(), + RESEAL_MANAGER), "ResealManager should have RESUME_ROLE on TWG after vote" + + no = nor.getNodeOperator(NETHERMIND_NO_ID, True) + + # Step 1.67: Rename Node Operator ID 25 from Nethermind to Twinstake + assert no[1] == NETHERMIND_NO_NAME_NEW + + # Step 1.68: Change Node Operator ID 25 reward address from 0x237DeE529A47750bEcdFa8A59a1D766e3e7B5F91 to 0x36201ed66DbC284132046ee8d99272F8eEeb24c8 + assert no[2] == NETHERMIND_NO_STAKING_REWARDS_ADDRESS_NEW + + # Step 1.69: Remove old Kiln guardian + assert dsm.isGuardian( + OLD_KILN_ADDRESS) is False, "Old Kiln address should be removed from guardians" + + # Step 1.70: Add new Kiln guardian + assert dsm.isGuardian( + NEW_KILN_ADDRESS) is True, "New Kiln address should be added to guardians" + assert dsm.getGuardianQuorum() == DSM_QUORUM_SIZE, "Guardians quorum should be 4" diff --git a/configs/config_mainnet.py b/configs/config_mainnet.py index 357b3653f..40768f64d 100644 --- a/configs/config_mainnet.py +++ b/configs/config_mainnet.py @@ -28,6 +28,7 @@ LIDO_IMPL_V1 = "0x47EbaB13B806773ec2A2d16873e2dF770D130b50" LEGACY_ORACLE_IMPL_V1 = "0x1430194905301504e8830ce4B0b0df7187E84AbD" NODE_OPERATORS_REGISTRY_IMPL_V1 = "0x5d39ABaa161e622B99D45616afC8B837E9F19a25" # was used in archived tests +VALIDATOR_EXIT_VERIFIER = "0xbDb567672c867DB533119C2dcD4FB9d8b44EC82f" # Aragon APM Repos REPO_APP_ID = "0xbe49cbb8894efb45c933fd09dc87bdd94909553a9e1f511d7fc10f3dad1564f2" @@ -72,6 +73,9 @@ EASYTRACK_MEV_BOOST_ADD_RELAYS_FACTORY = "0x00A3D6260f70b1660c8646Ef25D0820EFFd7bE60" EASYTRACK_MEV_BOOST_REMOVE_RELAYS_FACTORY = "0x9721c0f77E3Ea40eD592B9DCf3032DaF269c0306" EASYTRACK_MEV_BOOST_EDIT_RELAYS_FACTORY = "0x6b7863f2c7dEE99D3b744fDAEDbEB1aeCC025535" +EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0x8aa34dAaF0fC263203A15Bcfa0Ed926D466e59F3" +EASYTRACK_SIMPLE_DVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY = "0xB7668B5485d0f826B86a75b0115e088bB9ee03eE" +EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY = "0xBc5642bDD6F2a54b01A75605aAe9143525D97308" # Multisigs FINANCE_MULTISIG = "0x48F300bD3C52c7dA6aAbDE4B683dEB27d38B9ABb" @@ -103,7 +107,7 @@ # LidoLocator LIDO_LOCATOR = "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb" -LIDO_LOCATOR_IMPL = "0x3abc4764f0237923d52056cfba7e9aebf87113d3" +LIDO_LOCATOR_IMPL = "0x2C298963FB763f74765829722a1ebe0784f4F5Cf" # Other upgrade addresses LIDO_V2_UPGRADE_TEMPLATE = "0xa818fF9EC93122Bf9401ab4340C42De638CD600a" @@ -128,12 +132,13 @@ ORACLE_ARAGON_APP_ID = "0x8b47ba2a8454ec799cd91646e7ec47168e91fd139b23f017455f3e5898aaba93" # NodeOperatorsRegistry aka Curated Staking Module -NODE_OPERATORS_REGISTRY_IMPL = "0x1770044a38402e3CfCa2Fcfa0C84a093c9B42135" +NODE_OPERATORS_REGISTRY_IMPL = "0x6828b023e737f96B168aCd0b5c6351971a4F81aE" ## see NodeOperatorsRegistry's proxy appId() NODE_OPERATORS_REGISTRY_ARAGON_APP_ID = "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d" -NODE_OPERATORS_REGISTRY_VERSION = 3 +NODE_OPERATORS_REGISTRY_VERSION = 4 +NOR_EXIT_DEADLINE_IN_SEC = 172800 -CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY = 432000 +CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY = 0 CURATED_STAKING_MODULE_TARGET_SHARE_BP = 10000 CURATED_STAKING_MODULE_MODULE_FEE_BP = 500 CURATED_STAKING_MODULE_TREASURY_FEE_BP = 500 @@ -150,12 +155,12 @@ CURATED_STAKING_MODULE_MIN_DEPOSITS_BLOCK_DISTANCE = 25 # NodeOperatorsRegistry clone aka SimpleDVT -SIMPLE_DVT_IMPL = "0x1770044a38402e3CfCa2Fcfa0C84a093c9B42135" +SIMPLE_DVT_IMPL = "0x6828b023e737f96B168aCd0b5c6351971a4F81aE" SIMPLE_DVT_REPO = "0x2325b0a607808dE42D918DB07F925FFcCfBb2968" ## see SimpleDVT's proxy appId() SIMPLE_DVT_ARAGON_APP_NAME = "simple-dvt" SIMPLE_DVT_ARAGON_APP_ID = "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4" -SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY = 432000 +SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY = 0 SIMPLE_DVT_MODULE_TARGET_SHARE_BP = 400 SIMPLE_DVT_MODULE_MODULE_FEE_BP = 800 SIMPLE_DVT_MODULE_TREASURY_FEE_BP = 200 @@ -165,7 +170,7 @@ # bytes32("curated-onchain-v1") "0x637572617465642d6f6e636861696e2d76310000000000000000000000000000" ) -SIMPLE_DVT_VERSION = 3 +SIMPLE_DVT_VERSION = 4 SIMPLE_DVT_MODULE_PRIORITY_EXIT_SHARE_THRESHOLD = 444 SIMPLE_DVT_MODULE_MAX_DEPOSITS_PER_BLOCK = 150 SIMPLE_DVT_MODULE_MIN_DEPOSITS_BLOCK_DISTANCE = 25 @@ -176,8 +181,8 @@ CS_MODULE_NAME = "Community Staking" CS_MODULE_MODULE_FEE_BP = 600 CS_MODULE_TREASURY_FEE_BP = 400 -CS_MODULE_TARGET_SHARE_BP = 300 # Updated from 200 to 300 in vote 2025/07/16 -CS_MODULE_PRIORITY_EXIT_SHARE_THRESHOLD = 375 # Updated from 250 to 375 in vote 2025/07/16 +CS_MODULE_TARGET_SHARE_BP = 500 +CS_MODULE_PRIORITY_EXIT_SHARE_THRESHOLD = 625 CS_MODULE_MAX_DEPOSITS_PER_BLOCK = 30 CS_MODULE_MIN_DEPOSIT_BLOCK_DISTANCE = 25 @@ -192,6 +197,7 @@ NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP = 100 # 1% PREDICTION_DURATION_IN_SLOTS = 50400 FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT = 2250 # 10 days +EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS = 14 * 7200 # 14 days # OracleReportSanityChecker ORACLE_REPORT_SANITY_CHECKER = "0x6232397ebac4f5772e53285B26c47914E9461E75" @@ -222,29 +228,33 @@ DSM_GUARDIANS = [ "0x5fd0dDbC3351d009eb3f88DE7Cd081a614C519F1", "0x7912Fa976BcDe9c2cf728e213e892AD7588E6AaF", - "0x14D5d5B71E048d2D75a39FfC5B407e3a3AB6F314", + "0xd4EF84b638B334699bcf5AF4B0410B8CCD71943f", "0xf82D88217C249297C6037BA77CE34b3d8a90ab43", "0xa56b128Ea2Ea237052b0fA2a96a387C0E43157d8", - "0xd4EF84b638B334699bcf5AF4B0410B8CCD71943f", + "0x6d22aE126eB2c37F67a1391B37FF4f2863e61389", ] DSM_GUARDIAN_QUORUM = 4 # AccountingOracle # and its corresponding HashConsensus ACCOUNTING_ORACLE = "0x852deD011285fe67063a08005c71a85690503Cee" -ACCOUNTING_ORACLE_IMPL = "0x0e65898527E77210fB0133D00dd4C0E86Dc29bC7" +ACCOUNTING_ORACLE_IMPL = "0xE9906E543274cebcd335d2C560094089e9547e8d" HASH_CONSENSUS_FOR_AO = "0xD624B08C83bAECF0807Dd2c6880C3154a5F0B288" AO_EPOCHS_PER_FRAME = 225 AO_FAST_LANE_LENGTH_SLOTS = 100 -AO_CONSENSUS_VERSION = 3 +AO_CONSENSUS_VERSION = 4 # ValidatorsExitBusOracle VALIDATORS_EXIT_BUS_ORACLE = "0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e" -VALIDATORS_EXIT_BUS_ORACLE_IMPL = "0xA89Ea51FddE660f67d1850e03C9c9862d33Bc42c" +VALIDATORS_EXIT_BUS_ORACLE_IMPL = "0x905A211eD6830Cfc95643f0bE2ff64E7f3bf9b94" HASH_CONSENSUS_FOR_VEBO = "0x7FaDB6358950c5fAA66Cb5EB8eE5147De3df355a" VEBO_EPOCHS_PER_FRAME = 75 VEBO_FAST_LANE_LENGTH_SLOTS = 100 -VEBO_CONSENSUS_VERSION = 3 +VEBO_CONSENSUS_VERSION = 4 +MAX_VALIDATORS_PER_REPORT = 600 +MAX_EXIT_REQUESTS_LIMIT = 11200 +EXITS_PER_FRAME = 1 +FRAME_DURATION_IN_SEC = 48 # AccountingOracle and ValidatorsExitBusOracle @@ -274,9 +284,12 @@ WQ_ERC721_TOKEN_SYMBOL = "unstETH" WQ_ERC721_TOKEN_BASE_URI = "https://wq-api.lido.fi/v1/nft" +# TriggerableWithdrawalsGateway +TRIGGERABLE_WITHDRAWALS_GATEWAY = "0xDC00116a0D3E064427dA2600449cfD2566B3037B" + # WithdrawalsVault WITHDRAWAL_VAULT_IMPL_V1 = "0xe681faB8851484B57F32143FD78548f25fD59980" -WITHDRAWAL_VAULT_IMPL = "0xCC52f17756C04bBa7E377716d7062fC36D7f69Fd" +WITHDRAWAL_VAULT_IMPL = "0x7D2BAa6094E1C4B60Da4cbAF4A77C3f4694fD53D" # EIP712StETH EIP712_STETH = "0x8F73e4C2A6D852bb4ab2A45E6a9CF5715b3228B7" @@ -284,8 +297,8 @@ # StakingRouter STAKING_ROUTER = "0xFdDf38947aFB03C621C71b06C9C70bce73f12999" -STAKING_ROUTER_IMPL = "0x89eDa99C0551d4320b56F82DDE8dF2f8D2eF81aA" -STAKING_ROUTER_VERSION = 2 +STAKING_ROUTER_IMPL = "0x226f9265CBC37231882b7409658C18bB7738173A" +STAKING_ROUTER_VERSION = 3 # Not a precise but still some estimation of the fees. Assume here that all modules are filled @@ -323,11 +336,16 @@ # GateSeal GATE_SEAL_FACTORY = "0x6C82877cAC5a7A739f16Ca0A89c0A328B8764A24" -GATE_SEAL = "0xf9C9fDB4A5D2AA1D836D5370AB9b28BC1847e178" -GATE_SEAL_PAUSE_DURATION = 950400 # 11 days -GATE_SEAL_EXPIRY_TIMESTAMP = 1772323200 # 2026-03-01 00:00GMT +GATE_SEAL = "0x8A854C4E750CDf24f138f34A9061b2f556066912" +GATE_SEAL_PAUSE_DURATION = 1209600 +GATE_SEAL_EXPIRY_TIMESTAMP = 1789207187 GATE_SEAL_COMMITTEE = "0x8772E3a2D86B9347A2688f9bc1808A6d8917760C" +VEB_TWG_GATE_SEAL = "0xA6BC802fAa064414AA62117B4a53D27fFfF741F1" +VEB_TWG_GATE_SEAL_PAUSE_DURATION = 1209600 +VEB_TWG_GATE_SEAL_EXPIRY_TIMESTAMP = 1789207187 +VEB_TWG_SEAL_COMMITTEE = "0x8772E3a2D86B9347A2688f9bc1808A6d8917760C" + # Aragon Permissions test ACL_DEPLOY_BLOCK_NUMBER = 11473216 @@ -378,8 +396,16 @@ CS_FEE_DISTRIBUTOR_ADDRESS = "0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0" CS_FEE_ORACLE_ADDRESS = "0x4D4074628678Bd302921c20573EEa1ed38DdF7FB" CS_GATE_SEAL_ADDRESS = "0x16Dbd4B85a448bE564f1742d5c8cCdD2bB3185D0" -CS_VERIFIER_ADDRESS = "0xeC6Cc185f671F627fb9b6f06C8772755F587b05d" # Rotated from 0x0c345dFa318f9F4977cdd4f33d80F9D0ffA38e8B to 0xeC6Cc185f671F627fb9b6f06C8772755F587b05d in vote 2025/07/16 +CS_VERIFIER_ADDRESS = "0xeC6Cc185f671F627fb9b6f06C8772755F587b05d" CS_VERIFIER_ADDRESS_OLD = "0x3Dfc50f22aCA652a0a6F28a0F892ab62074b5583" +CS_PARAMS_REGISTRY_ADDRESS = "0x9D28ad303C90DF524BA960d7a2DAC56DcC31e428" +CS_EXIT_PENALTIES_ADDRESS = "0x06cd61045f958A209a0f8D746e103eCc625f4193" +CS_STRIKES_ADDRESS = "0xaa328816027F2D32B9F56d190BC9Fa4A5C07637f" +CS_EJECTOR_ADDRESS = "0xc72b58aa02E0e98cF8A4a0E9Dce75e763800802C" +CS_VETTED_GATE_ADDRESS = "0xB314D4A76C457c93150d308787939063F4Cc67E0" +CS_PERMISSIONLESS_GATE_ADDRESS = "0xcF33a38111d0B1246A3F38a838fb41D626B454f0" +CS_VERIFIER_V2_ADDRESS = "0xdC5FE1782B6943f318E05230d688713a560063DC" +CS_GATE_SEAL_V2_ADDRESS = "0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3" # DualGovernance DUAL_GOVERNANCE = "0xC1db28B3301331277e307FDCfF8DE28242A4486E" @@ -400,7 +426,6 @@ ESCROW_VETO_SIGNALLING = "0x165813A31446a98c84E20Dda8C101BB3C8228e1c" MAX_MIN_ASSETS_LOCK_DURATION = 4147200 - DUAL_GOVERNANCE_CONFIG_PROVIDER_VALUES = { "FIRST_SEAL_RAGE_QUIT_SUPPORT": 1 * 10 ** 16, # 1% in PercentD16 "SECOND_SEAL_RAGE_QUIT_SUPPORT": 10 * 10 ** 16, # 10% in PercentD16 @@ -485,7 +510,6 @@ ], } - DUAL_GOVERNANCE_VALUES = { "MAX_TIEBREAKER_ACTIVATION_TIMEOUT": 63072000, # 2 years "MIN_TIEBREAKER_ACTIVATION_TIMEOUT": 15768000, # 6 months @@ -494,6 +518,6 @@ "TIEBREAKER_DETAILS": { "TIEBREAKER_COMMITTEE": TIEBREAKER_VALUES["CORE_COMMITTEE"]["ADDRESS"], "TIEBREAKER_ACTIVATION_TIMEOUT": 31536000, # 1 year - "WITHDRAWAL_BLOCKERS": (WITHDRAWAL_QUEUE, VALIDATORS_EXIT_BUS_ORACLE), + "WITHDRAWAL_BLOCKERS": (WITHDRAWAL_QUEUE, VALIDATORS_EXIT_BUS_ORACLE, TRIGGERABLE_WITHDRAWALS_GATEWAY), } -} \ No newline at end of file +} diff --git a/interfaces/CSEjector.json b/interfaces/CSEjector.json index c27efed2b..50b020267 100644 --- a/interfaces/CSEjector.json +++ b/interfaces/CSEjector.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"module","type":"address","internalType":"address"},{"name":"strikes","type":"address","internalType":"address"},{"name":"twg","type":"address","internalType":"address"},{"name":"stakingModuleId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_INFINITELY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"RESUME_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"STAKING_MODULE_ID","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"STRIKES","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"STRIKES_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"TWG","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ITriggerableWithdrawalsGateway"}],"stateMutability":"view"},{"type":"function","name":"VOLUNTARY_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"ejectBadPerformer","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"},{"name":"refundRecipient","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"getResumeSinceTimestamp","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[{"name":"admin","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"isPaused","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"pauseFor","inputs":[{"name":"duration","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resume","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"voluntaryEject","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"startFrom","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"refundRecipient","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"voluntaryEjectByArray","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndices","type":"uint256[]","internalType":"uint256[]"},{"name":"refundRecipient","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"payable"},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"name":"duration","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Resumed","inputs":[],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AlreadyWithdrawn","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"NodeOperatorDoesNotExist","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"PauseUntilMustBeInFuture","inputs":[]},{"type":"error","name":"PausedExpected","inputs":[]},{"type":"error","name":"ResumedExpected","inputs":[]},{"type":"error","name":"SenderIsNotEligible","inputs":[]},{"type":"error","name":"SenderIsNotStrikes","inputs":[]},{"type":"error","name":"SigningKeysInvalidOffset","inputs":[]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroPauseDuration","inputs":[]},{"type":"error","name":"ZeroStrikesAddress","inputs":[]},{"type":"error","name":"ZeroTWGAddress","inputs":[]}] +[{"inputs":[{"internalType":"address","name":"module","type":"address"},{"internalType":"address","name":"strikes","type":"address"},{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AlreadyWithdrawn","type":"error"},{"inputs":[],"name":"NodeOperatorDoesNotExist","type":"error"},{"inputs":[],"name":"NothingToEject","type":"error"},{"inputs":[],"name":"PauseUntilMustBeInFuture","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderIsNotEligible","type":"error"},{"inputs":[],"name":"SenderIsNotStrikes","type":"error"},{"inputs":[],"name":"SigningKeysInvalidOffset","type":"error"},{"inputs":[],"name":"ZeroAdminAddress","type":"error"},{"inputs":[],"name":"ZeroModuleAddress","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroStrikesAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE","outputs":[{"internalType":"contract ICSModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_INFINITELY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVERER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRIKES","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRIKES_EXIT_TYPE_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOLUNTARY_EXIT_TYPE_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keyIndex","type":"uint256"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"ejectBadPerformer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getResumeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"pauseFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"triggerableWithdrawalsGateway","outputs":[{"internalType":"contract ITriggerableWithdrawalsGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"startFrom","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"voluntaryEject","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256[]","name":"keyIndices","type":"uint256[]"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"voluntaryEjectByArray","outputs":[],"stateMutability":"payable","type":"function"}] diff --git a/interfaces/CSExitPenalties.json b/interfaces/CSExitPenalties.json index e45976af2..12a6b410e 100644 --- a/interfaces/CSExitPenalties.json +++ b/interfaces/CSExitPenalties.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"module","type":"address","internalType":"address"},{"name":"parametersRegistry","type":"address","internalType":"address"},{"name":"strikes","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ACCOUNTING","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSAccounting"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PARAMETERS_REGISTRY","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSParametersRegistry"}],"stateMutability":"view"},{"type":"function","name":"STRIKES","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"STRIKES_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"VOLUNTARY_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"getExitPenaltyInfo","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"tuple","internalType":"struct ExitPenaltyInfo","components":[{"name":"delayPenalty","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]},{"name":"strikesPenalty","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]},{"name":"withdrawalRequestFee","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]}]}],"stateMutability":"view"},{"type":"function","name":"isValidatorExitDelayPenaltyApplicable","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"processExitDelayReport","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processStrikesReport","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processTriggeredExit","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"withdrawalRequestPaidFee","type":"uint256","internalType":"uint256"},{"name":"exitType","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"StrikesPenaltyProcessed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"strikesPenalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"TriggeredExitFeeRecorded","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"exitType","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"withdrawalRequestFee","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ValidatorExitDelayProcessed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"delayPenalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"SafeCastOverflowedUintDowncast","inputs":[{"name":"bits","type":"uint8","internalType":"uint8"},{"name":"value","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"SenderIsNotModule","inputs":[]},{"type":"error","name":"SenderIsNotStrikes","inputs":[]},{"type":"error","name":"ValidatorExitDelayAlreadyReported","inputs":[]},{"type":"error","name":"ValidatorExitDelayNotApplicable","inputs":[]},{"type":"error","name":"ZeroAccountingAddress","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroParametersRegistryAddress","inputs":[]},{"type":"error","name":"ZeroStrikesAddress","inputs":[]}] +[{"type":"constructor","inputs":[{"name":"module","type":"address","internalType":"address"},{"name":"parametersRegistry","type":"address","internalType":"address"},{"name":"strikes","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ACCOUNTING","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSAccounting"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PARAMETERS_REGISTRY","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSParametersRegistry"}],"stateMutability":"view"},{"type":"function","name":"STRIKES","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"STRIKES_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"VOLUNTARY_EXIT_TYPE_ID","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"getExitPenaltyInfo","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"tuple","internalType":"struct ExitPenaltyInfo","components":[{"name":"delayPenalty","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]},{"name":"strikesPenalty","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]},{"name":"withdrawalRequestFee","type":"tuple","internalType":"struct MarkedUint248","components":[{"name":"value","type":"uint248","internalType":"uint248"},{"name":"isValue","type":"bool","internalType":"bool"}]}]}],"stateMutability":"view"},{"type":"function","name":"isValidatorExitDelayPenaltyApplicable","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"processExitDelayReport","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processStrikesReport","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processTriggeredExit","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"withdrawalRequestPaidFee","type":"uint256","internalType":"uint256"},{"name":"exitType","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"StrikesPenaltyProcessed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"strikesPenalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"TriggeredExitFeeRecorded","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"exitType","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"withdrawalRequestPaidFee","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"withdrawalRequestRecordedFee","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ValidatorExitDelayProcessed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"delayPenalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"SafeCastOverflowedUintDowncast","inputs":[{"name":"bits","type":"uint8","internalType":"uint8"},{"name":"value","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"SenderIsNotModule","inputs":[]},{"type":"error","name":"SenderIsNotStrikes","inputs":[]},{"type":"error","name":"ValidatorExitDelayNotApplicable","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroParametersRegistryAddress","inputs":[]},{"type":"error","name":"ZeroStrikesAddress","inputs":[]}] diff --git a/interfaces/CSModule.json b/interfaces/CSModule.json index 67ac8332a..0652581d9 100644 --- a/interfaces/CSModule.json +++ b/interfaces/CSModule.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"moduleType","type":"bytes32","internalType":"bytes32"},{"name":"lidoLocator","type":"address","internalType":"address"},{"name":"parametersRegistry","type":"address","internalType":"address"},{"name":"_accounting","type":"address","internalType":"address"},{"name":"exitPenalties","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ACCOUNTING","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSAccounting"}],"stateMutability":"view"},{"type":"function","name":"CREATE_NODE_OPERATOR_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"DEPOSIT_SIZE","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"EXIT_PENALTIES","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSExitPenalties"}],"stateMutability":"view"},{"type":"function","name":"LIDO_LOCATOR","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ILidoLocator"}],"stateMutability":"view"},{"type":"function","name":"PARAMETERS_REGISTRY","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSParametersRegistry"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_INFINITELY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"QUEUE_LEGACY_PRIORITY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"QUEUE_LOWEST_PRIORITY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"RECOVERER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"REPORT_EL_REWARDS_STEALING_PENALTY_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"RESUME_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"SETTLE_EL_REWARDS_STEALING_PENALTY_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"STAKING_ROUTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"STETH","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IStETH"}],"stateMutability":"view"},{"type":"function","name":"VERIFIER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"accounting","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSAccounting"}],"stateMutability":"view"},{"type":"function","name":"addValidatorKeysETH","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"addValidatorKeysStETH","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"addValidatorKeysWstETH","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"cancelELRewardsStealingPenalty","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"changeNodeOperatorRewardAddress","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"newAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"cleanDepositQueue","inputs":[{"name":"maxItems","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"removed","type":"uint256","internalType":"uint256"},{"name":"lastRemovedAtDepth","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"compensateELRewardsStealingPenalty","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"confirmNodeOperatorManagerAddressChange","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"confirmNodeOperatorRewardAddressChange","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"createNodeOperator","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"decreaseVettedSigningKeysCount","inputs":[{"name":"nodeOperatorIds","type":"bytes","internalType":"bytes"},{"name":"vettedSigningKeysCounts","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"depositQueueItem","inputs":[{"name":"queuePriority","type":"uint256","internalType":"uint256"},{"name":"index","type":"uint128","internalType":"uint128"}],"outputs":[{"name":"","type":"uint256","internalType":"Batch"}],"stateMutability":"view"},{"type":"function","name":"depositQueuePointers","inputs":[{"name":"queuePriority","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"head","type":"uint128","internalType":"uint128"},{"name":"tail","type":"uint128","internalType":"uint128"}],"stateMutability":"view"},{"type":"function","name":"exitDeadlineThreshold","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"finalizeUpgradeV2","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getActiveNodeOperatorsCount","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getInitializedVersion","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperator","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple","internalType":"struct NodeOperator","components":[{"name":"totalAddedKeys","type":"uint32","internalType":"uint32"},{"name":"totalWithdrawnKeys","type":"uint32","internalType":"uint32"},{"name":"totalDepositedKeys","type":"uint32","internalType":"uint32"},{"name":"totalVettedKeys","type":"uint32","internalType":"uint32"},{"name":"stuckValidatorsCount","type":"uint32","internalType":"uint32"},{"name":"depositableValidatorsCount","type":"uint32","internalType":"uint32"},{"name":"targetLimit","type":"uint32","internalType":"uint32"},{"name":"targetLimitMode","type":"uint8","internalType":"uint8"},{"name":"totalExitedKeys","type":"uint32","internalType":"uint32"},{"name":"enqueuedCount","type":"uint32","internalType":"uint32"},{"name":"managerAddress","type":"address","internalType":"address"},{"name":"proposedManagerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"proposedRewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"},{"name":"usedPriorityQueue","type":"bool","internalType":"bool"}]}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorIds","inputs":[{"name":"offset","type":"uint256","internalType":"uint256"},{"name":"limit","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"nodeOperatorIds","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorIsActive","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorManagementProperties","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorNonWithdrawnKeys","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorSummary","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"targetLimitMode","type":"uint256","internalType":"uint256"},{"name":"targetValidatorsCount","type":"uint256","internalType":"uint256"},{"name":"stuckValidatorsCount","type":"uint256","internalType":"uint256"},{"name":"refundedValidatorsCount","type":"uint256","internalType":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"totalExitedValidators","type":"uint256","internalType":"uint256"},{"name":"totalDepositedValidators","type":"uint256","internalType":"uint256"},{"name":"depositableValidatorsCount","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorTotalDepositedKeys","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"totalDepositedKeys","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getNodeOperatorsCount","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getNonce","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getResumeSinceTimestamp","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getSigningKeys","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"startIndex","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getSigningKeysWithSignatures","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"startIndex","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"keys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getStakingModuleSummary","inputs":[],"outputs":[{"name":"totalExitedValidators","type":"uint256","internalType":"uint256"},{"name":"totalDepositedValidators","type":"uint256","internalType":"uint256"},{"name":"depositableValidatorsCount","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getType","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[{"name":"admin","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"isPaused","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isValidatorExitDelayPenaltyApplicable","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isValidatorWithdrawn","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"legacyQueue","inputs":[],"outputs":[{"name":"head","type":"uint128","internalType":"uint128"},{"name":"tail","type":"uint128","internalType":"uint128"}],"stateMutability":"view"},{"type":"function","name":"migrateToPriorityQueue","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"obtainDepositData","inputs":[{"name":"depositsCount","type":"uint256","internalType":"uint256"},{"name":"","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"}],"stateMutability":"nonpayable"},{"type":"function","name":"onExitedAndStuckValidatorsCountsUpdated","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onRewardsMinted","inputs":[{"name":"totalShares","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onValidatorExitTriggered","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"withdrawalRequestPaidFee","type":"uint256","internalType":"uint256"},{"name":"exitType","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onWithdrawalCredentialsChanged","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"pauseFor","inputs":[{"name":"duration","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"proposeNodeOperatorManagerAddressChange","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"proposedAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"proposeNodeOperatorRewardAddressChange","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"proposedAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"recoverERC1155","inputs":[{"name":"token","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"recoverERC20","inputs":[{"name":"token","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"recoverERC721","inputs":[{"name":"token","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"recoverEther","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"removeKeys","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"startIndex","type":"uint256","internalType":"uint256"},{"name":"keysCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"reportELRewardsStealingPenalty","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"blockHash","type":"bytes32","internalType":"bytes32"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"reportValidatorExitDelay","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"bytes","internalType":"bytes"},{"name":"eligibleToExitInSec","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resetNodeOperatorManagerAddress","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resume","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"settleELRewardsStealingPenalty","inputs":[{"name":"nodeOperatorIds","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"submitWithdrawals","inputs":[{"name":"withdrawalsInfo","type":"tuple[]","internalType":"struct ValidatorWithdrawalInfo[]","components":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"isSlashed","type":"bool","internalType":"bool"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"unsafeUpdateValidatorsCount","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"exitedValidatorsKeysCount","type":"uint256","internalType":"uint256"},{"name":"stuckValidatorsKeysCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateDepositableValidatorsCount","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateExitedValidatorsCount","inputs":[{"name":"nodeOperatorIds","type":"bytes","internalType":"bytes"},{"name":"exitedValidatorsCounts","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateTargetValidatorsLimits","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"targetLimitMode","type":"uint256","internalType":"uint256"},{"name":"targetLimit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"BatchEnqueued","inputs":[{"name":"queuePriority","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"count","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DelayedValidatorExitPenalized","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"penaltyValue","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DepositableSigningKeysCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"depositableKeysCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DepositedSigningKeysCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"depositedKeysCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ELRewardsStealingPenaltyCancelled","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ELRewardsStealingPenaltyCompensated","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ELRewardsStealingPenaltyReported","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"proposedBlockHash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"stolenAmount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ELRewardsStealingPenaltySettled","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ERC1155Recovered","inputs":[{"name":"token","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"recipient","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ERC20Recovered","inputs":[{"name":"token","type":"address","indexed":true,"internalType":"address"},{"name":"recipient","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ERC721Recovered","inputs":[{"name":"token","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"recipient","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"EtherRecovered","inputs":[{"name":"recipient","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ExitedSigningKeysCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"exitedKeysCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"KeyRemovalChargeApplied","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"NodeOperatorAdded","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"managerAddress","type":"address","indexed":true,"internalType":"address"},{"name":"rewardAddress","type":"address","indexed":true,"internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"type":"event","name":"NodeOperatorManagerAddressChangeProposed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"oldProposedAddress","type":"address","indexed":true,"internalType":"address"},{"name":"newProposedAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"NodeOperatorManagerAddressChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"oldAddress","type":"address","indexed":true,"internalType":"address"},{"name":"newAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"NodeOperatorRewardAddressChangeProposed","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"oldProposedAddress","type":"address","indexed":true,"internalType":"address"},{"name":"newProposedAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"NodeOperatorRewardAddressChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"oldAddress","type":"address","indexed":true,"internalType":"address"},{"name":"newAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"NonceChanged","inputs":[{"name":"nonce","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"name":"duration","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ReferrerSet","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"referrer","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Resumed","inputs":[],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"SigningKeyAdded","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"SigningKeyRemoved","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"StETHSharesRecovered","inputs":[{"name":"recipient","type":"address","indexed":true,"internalType":"address"},{"name":"shares","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"TargetValidatorsCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"targetLimitMode","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"targetValidatorsCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"TotalSigningKeysCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"totalKeysCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"VettedSigningKeysCountChanged","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"vettedKeysCount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"VettedSigningKeysCountDecreased","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"WithdrawalSubmitted","inputs":[{"name":"nodeOperatorId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"keyIndex","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"pubkey","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AlreadyProposed","inputs":[]},{"type":"error","name":"AlreadyWithdrawn","inputs":[]},{"type":"error","name":"CannotAddKeys","inputs":[]},{"type":"error","name":"EmptyKey","inputs":[]},{"type":"error","name":"ExitedKeysDecrease","inputs":[]},{"type":"error","name":"ExitedKeysHigherThanTotalDeposited","inputs":[]},{"type":"error","name":"FailedToSendEther","inputs":[]},{"type":"error","name":"InvalidAmount","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidInput","inputs":[]},{"type":"error","name":"InvalidKeysCount","inputs":[]},{"type":"error","name":"InvalidLength","inputs":[]},{"type":"error","name":"InvalidReportData","inputs":[]},{"type":"error","name":"InvalidVetKeysPointer","inputs":[]},{"type":"error","name":"KeysLimitExceeded","inputs":[]},{"type":"error","name":"MethodCallIsNotAllowed","inputs":[]},{"type":"error","name":"NodeOperatorDoesNotExist","inputs":[]},{"type":"error","name":"NotAllowedToRecover","inputs":[]},{"type":"error","name":"NotEnoughKeys","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"PauseUntilMustBeInFuture","inputs":[]},{"type":"error","name":"PausedExpected","inputs":[]},{"type":"error","name":"PriorityQueueAlreadyUsed","inputs":[]},{"type":"error","name":"QueueIsEmpty","inputs":[]},{"type":"error","name":"QueueLookupNoLimit","inputs":[]},{"type":"error","name":"ResumedExpected","inputs":[]},{"type":"error","name":"SameAddress","inputs":[]},{"type":"error","name":"SenderIsNotEligible","inputs":[]},{"type":"error","name":"SenderIsNotManagerAddress","inputs":[]},{"type":"error","name":"SenderIsNotProposedAddress","inputs":[]},{"type":"error","name":"SenderIsNotRewardAddress","inputs":[]},{"type":"error","name":"SigningKeysInvalidOffset","inputs":[]},{"type":"error","name":"ZeroAccountingAddress","inputs":[]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroExitPenaltiesAddress","inputs":[]},{"type":"error","name":"ZeroLocatorAddress","inputs":[]},{"type":"error","name":"ZeroParametersRegistryAddress","inputs":[]},{"type":"error","name":"ZeroPauseDuration","inputs":[]},{"type":"error","name":"ZeroRewardAddress","inputs":[]},{"type":"error","name":"ZeroSenderAddress","inputs":[]}] +[{"inputs":[{"internalType":"bytes32","name":"moduleType","type":"bytes32"},{"internalType":"address","name":"lidoLocator","type":"address"},{"internalType":"address","name":"parametersRegistry","type":"address"},{"internalType":"address","name":"_accounting","type":"address"},{"internalType":"address","name":"exitPenalties","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AlreadyProposed","type":"error"},{"inputs":[],"name":"CannotAddKeys","type":"error"},{"inputs":[],"name":"EmptyKey","type":"error"},{"inputs":[],"name":"ExitedKeysDecrease","type":"error"},{"inputs":[],"name":"ExitedKeysHigherThanTotalDeposited","type":"error"},{"inputs":[],"name":"FailedToSendEther","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidKeysCount","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"InvalidVetKeysPointer","type":"error"},{"inputs":[],"name":"KeysLimitExceeded","type":"error"},{"inputs":[],"name":"MethodCallIsNotAllowed","type":"error"},{"inputs":[],"name":"NoQueuedKeysToMigrate","type":"error"},{"inputs":[],"name":"NodeOperatorDoesNotExist","type":"error"},{"inputs":[],"name":"NotAllowedToRecover","type":"error"},{"inputs":[],"name":"NotEligibleForPriorityQueue","type":"error"},{"inputs":[],"name":"NotEnoughKeys","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PauseUntilMustBeInFuture","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[],"name":"PriorityQueueAlreadyUsed","type":"error"},{"inputs":[],"name":"PriorityQueueMaxDepositsUsed","type":"error"},{"inputs":[],"name":"QueueIsEmpty","type":"error"},{"inputs":[],"name":"QueueLookupNoLimit","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[],"name":"SameAddress","type":"error"},{"inputs":[],"name":"SenderIsNotEligible","type":"error"},{"inputs":[],"name":"SenderIsNotManagerAddress","type":"error"},{"inputs":[],"name":"SenderIsNotProposedAddress","type":"error"},{"inputs":[],"name":"SenderIsNotRewardAddress","type":"error"},{"inputs":[],"name":"SigningKeysInvalidOffset","type":"error"},{"inputs":[],"name":"ZeroAccountingAddress","type":"error"},{"inputs":[],"name":"ZeroAdminAddress","type":"error"},{"inputs":[],"name":"ZeroExitPenaltiesAddress","type":"error"},{"inputs":[],"name":"ZeroLocatorAddress","type":"error"},{"inputs":[],"name":"ZeroParametersRegistryAddress","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRewardAddress","type":"error"},{"inputs":[],"name":"ZeroSenderAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queuePriority","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"BatchEnqueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositableKeysCount","type":"uint256"}],"name":"DepositableSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositedKeysCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ELRewardsStealingPenaltyCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ELRewardsStealingPenaltyCompensated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"proposedBlockHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"stolenAmount","type":"uint256"}],"name":"ELRewardsStealingPenaltyReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"ELRewardsStealingPenaltySettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC1155Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"ERC721Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exitedKeysCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"KeyRemovalChargeApplied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"managerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"rewardAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldProposedAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newProposedAddress","type":"address"}],"name":"NodeOperatorManagerAddressChangeProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"NodeOperatorManagerAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldProposedAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newProposedAddress","type":"address"}],"name":"NodeOperatorRewardAddressChangeProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"NodeOperatorRewardAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"}],"name":"ReferrerSet","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"SigningKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"SigningKeyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"StETHSharesRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetLimitMode","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalKeysCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vettedKeysCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"VettedSigningKeysCountDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"keyIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"WithdrawalSubmitted","type":"event"},{"inputs":[],"name":"ACCOUNTING","outputs":[{"internalType":"contract ICSAccounting","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATE_NODE_OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXIT_PENALTIES","outputs":[{"internalType":"contract ICSExitPenalties","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DISTRIBUTOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIDO_LOCATOR","outputs":[{"internalType":"contract ILidoLocator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARAMETERS_REGISTRY","outputs":[{"internalType":"contract ICSParametersRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_INFINITELY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUEUE_LEGACY_PRIORITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUEUE_LOWEST_PRIORITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVERER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EL_REWARDS_STEALING_PENALTY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SETTLE_EL_REWARDS_STEALING_PENALTY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFIER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accounting","outputs":[{"internalType":"contract ICSAccounting","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"addValidatorKeysETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"}],"name":"addValidatorKeysStETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"}],"name":"addValidatorKeysWstETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"cancelELRewardsStealingPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"newAddress","type":"address"}],"name":"changeNodeOperatorRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxItems","type":"uint256"}],"name":"cleanDepositQueue","outputs":[{"internalType":"uint256","name":"removed","type":"uint256"},{"internalType":"uint256","name":"lastRemovedAtDepth","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"compensateELRewardsStealingPenalty","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"confirmNodeOperatorManagerAddressChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"confirmNodeOperatorRewardAddressChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"internalType":"address","name":"referrer","type":"address"}],"name":"createNodeOperator","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"vettedSigningKeysCounts","type":"bytes"}],"name":"decreaseVettedSigningKeysCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"queuePriority","type":"uint256"},{"internalType":"uint128","name":"index","type":"uint128"}],"name":"depositQueueItem","outputs":[{"internalType":"Batch","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"queuePriority","type":"uint256"}],"name":"depositQueuePointers","outputs":[{"internalType":"uint128","name":"head","type":"uint128"},{"internalType":"uint128","name":"tail","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"exitDeadlineThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalizeUpgradeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitializedVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperator","outputs":[{"components":[{"internalType":"uint32","name":"totalAddedKeys","type":"uint32"},{"internalType":"uint32","name":"totalWithdrawnKeys","type":"uint32"},{"internalType":"uint32","name":"totalDepositedKeys","type":"uint32"},{"internalType":"uint32","name":"totalVettedKeys","type":"uint32"},{"internalType":"uint32","name":"stuckValidatorsCount","type":"uint32"},{"internalType":"uint32","name":"depositableValidatorsCount","type":"uint32"},{"internalType":"uint32","name":"targetLimit","type":"uint32"},{"internalType":"uint8","name":"targetLimitMode","type":"uint8"},{"internalType":"uint32","name":"totalExitedKeys","type":"uint32"},{"internalType":"uint32","name":"enqueuedCount","type":"uint32"},{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"proposedManagerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"address","name":"proposedRewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"},{"internalType":"bool","name":"usedPriorityQueue","type":"bool"}],"internalType":"struct NodeOperator","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"internalType":"uint256[]","name":"nodeOperatorIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorManagementProperties","outputs":[{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorNonWithdrawnKeys","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"internalType":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"refundedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckPenaltyEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorTotalDepositedKeys","outputs":[{"internalType":"uint256","name":"totalDepositedKeys","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getResumeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"}],"name":"getSigningKeys","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"}],"name":"getSigningKeysWithSignatures","outputs":[{"internalType":"bytes","name":"keys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleSummary","outputs":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"uint256","name":"eligibleToExitInSec","type":"uint256"}],"name":"isValidatorExitDelayPenaltyApplicable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keyIndex","type":"uint256"}],"name":"isValidatorWithdrawn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"migrateToPriorityQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositsCount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onExitedAndStuckValidatorsCountsUpdated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"onRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"uint256","name":"withdrawalRequestPaidFee","type":"uint256"},{"internalType":"uint256","name":"exitType","type":"uint256"}],"name":"onValidatorExitTriggered","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"pauseFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"proposedAddress","type":"address"}],"name":"proposeNodeOperatorManagerAddressChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"address","name":"proposedAddress","type":"address"}],"name":"proposeNodeOperatorRewardAddressChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"keysCount","type":"uint256"}],"name":"removeKeys","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reportELRewardsStealingPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"uint256","name":"eligibleToExitInSec","type":"uint256"}],"name":"reportValidatorExitDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"resetNodeOperatorManagerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nodeOperatorIds","type":"uint256[]"}],"name":"settleELRewardsStealingPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"keyIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidatorWithdrawalInfo[]","name":"withdrawalsInfo","type":"tuple[]"}],"name":"submitWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsKeysCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"name":"updateDepositableValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetLimit","type":"uint256"}],"name":"updateTargetValidatorsLimits","outputs":[],"stateMutability":"nonpayable","type":"function"}] diff --git a/interfaces/CSParametersRegistry.json b/interfaces/CSParametersRegistry.json new file mode 100644 index 000000000..8a41979fb --- /dev/null +++ b/interfaces/CSParametersRegistry.json @@ -0,0 +1 @@ +[{"type":"constructor","inputs":[{"name":"queueLowestPriority","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"QUEUE_LEGACY_PRIORITY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"QUEUE_LOWEST_PRIORITY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultAllowedExitDelay","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultBadPerformancePenalty","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultElRewardsStealingAdditionalFine","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultExitDelayPenalty","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultKeyRemovalCharge","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultKeysLimit","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultMaxWithdrawalRequestFee","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultPerformanceCoefficients","inputs":[],"outputs":[{"name":"attestationsWeight","type":"uint32","internalType":"uint32"},{"name":"blocksWeight","type":"uint32","internalType":"uint32"},{"name":"syncWeight","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"defaultPerformanceLeeway","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultQueueConfig","inputs":[],"outputs":[{"name":"priority","type":"uint32","internalType":"uint32"},{"name":"maxDeposits","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"defaultRewardShare","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"defaultStrikesParams","inputs":[],"outputs":[{"name":"lifetime","type":"uint32","internalType":"uint32"},{"name":"threshold","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"getAllowedExitDelay","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"delay","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getBadPerformancePenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"penalty","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getElRewardsStealingAdditionalFine","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"fine","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getExitDelayPenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"penalty","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getInitializedVersion","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"getKeyRemovalCharge","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"keyRemovalCharge","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getKeysLimit","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"limit","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getMaxWithdrawalRequestFee","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"fee","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getPerformanceCoefficients","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"attestationsWeight","type":"uint256","internalType":"uint256"},{"name":"blocksWeight","type":"uint256","internalType":"uint256"},{"name":"syncWeight","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getPerformanceLeewayData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"data","type":"tuple[]","internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"stateMutability":"view"},{"type":"function","name":"getQueueConfig","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"queuePriority","type":"uint32","internalType":"uint32"},{"name":"maxDeposits","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"type":"function","name":"getRewardShareData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"data","type":"tuple[]","internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getStrikesParams","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"lifetime","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[{"name":"admin","type":"address","internalType":"address"},{"name":"data","type":"tuple","internalType":"struct ICSParametersRegistry.InitializationData","components":[{"name":"keyRemovalCharge","type":"uint256","internalType":"uint256"},{"name":"elRewardsStealingAdditionalFine","type":"uint256","internalType":"uint256"},{"name":"keysLimit","type":"uint256","internalType":"uint256"},{"name":"rewardShare","type":"uint256","internalType":"uint256"},{"name":"performanceLeeway","type":"uint256","internalType":"uint256"},{"name":"strikesLifetime","type":"uint256","internalType":"uint256"},{"name":"strikesThreshold","type":"uint256","internalType":"uint256"},{"name":"defaultQueuePriority","type":"uint256","internalType":"uint256"},{"name":"defaultQueueMaxDeposits","type":"uint256","internalType":"uint256"},{"name":"badPerformancePenalty","type":"uint256","internalType":"uint256"},{"name":"attestationsWeight","type":"uint256","internalType":"uint256"},{"name":"blocksWeight","type":"uint256","internalType":"uint256"},{"name":"syncWeight","type":"uint256","internalType":"uint256"},{"name":"defaultAllowedExitDelay","type":"uint256","internalType":"uint256"},{"name":"defaultExitDelayPenalty","type":"uint256","internalType":"uint256"},{"name":"defaultMaxWithdrawalRequestFee","type":"uint256","internalType":"uint256"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setAllowedExitDelay","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"delay","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setBadPerformancePenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"penalty","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultAllowedExitDelay","inputs":[{"name":"delay","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultBadPerformancePenalty","inputs":[{"name":"penalty","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultElRewardsStealingAdditionalFine","inputs":[{"name":"fine","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultExitDelayPenalty","inputs":[{"name":"penalty","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultKeyRemovalCharge","inputs":[{"name":"keyRemovalCharge","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultKeysLimit","inputs":[{"name":"limit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultMaxWithdrawalRequestFee","inputs":[{"name":"fee","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultPerformanceCoefficients","inputs":[{"name":"attestationsWeight","type":"uint256","internalType":"uint256"},{"name":"blocksWeight","type":"uint256","internalType":"uint256"},{"name":"syncWeight","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultPerformanceLeeway","inputs":[{"name":"leeway","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultQueueConfig","inputs":[{"name":"priority","type":"uint256","internalType":"uint256"},{"name":"maxDeposits","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultRewardShare","inputs":[{"name":"share","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setDefaultStrikesParams","inputs":[{"name":"lifetime","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setElRewardsStealingAdditionalFine","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"fine","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setExitDelayPenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"penalty","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setKeyRemovalCharge","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"keyRemovalCharge","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setKeysLimit","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"limit","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMaxWithdrawalRequestFee","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"fee","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setPerformanceCoefficients","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"attestationsWeight","type":"uint256","internalType":"uint256"},{"name":"blocksWeight","type":"uint256","internalType":"uint256"},{"name":"syncWeight","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setPerformanceLeewayData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"data","type":"tuple[]","internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setQueueConfig","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"priority","type":"uint256","internalType":"uint256"},{"name":"maxDeposits","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setRewardShareData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"data","type":"tuple[]","internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setStrikesParams","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"},{"name":"lifetime","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"unsetAllowedExitDelay","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetBadPerformancePenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetElRewardsStealingAdditionalFine","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetExitDelayPenalty","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetKeyRemovalCharge","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetKeysLimit","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetMaxWithdrawalRequestFee","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetPerformanceCoefficients","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetPerformanceLeewayData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetQueueConfig","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetRewardShareData","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unsetStrikesParams","inputs":[{"name":"curveId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"AllowedExitDelaySet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"delay","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"AllowedExitDelayUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"BadPerformancePenaltySet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"penalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"BadPerformancePenaltyUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultAllowedExitDelaySet","inputs":[{"name":"delay","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultBadPerformancePenaltySet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultElRewardsStealingAdditionalFineSet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultExitDelayPenaltySet","inputs":[{"name":"penalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultKeyRemovalChargeSet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultKeysLimitSet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultMaxWithdrawalRequestFeeSet","inputs":[{"name":"fee","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultPerformanceCoefficientsSet","inputs":[{"name":"attestationsWeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"blocksWeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"syncWeight","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultPerformanceLeewaySet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultQueueConfigSet","inputs":[{"name":"priority","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"maxDeposits","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultRewardShareSet","inputs":[{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"DefaultStrikesParamsSet","inputs":[{"name":"lifetime","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"threshold","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ElRewardsStealingAdditionalFineSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"fine","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ElRewardsStealingAdditionalFineUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ExitDelayPenaltySet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"penalty","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ExitDelayPenaltyUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"KeyRemovalChargeSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"keyRemovalCharge","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"KeyRemovalChargeUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"KeysLimitSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"limit","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"KeysLimitUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"MaxWithdrawalRequestFeeSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"fee","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"MaxWithdrawalRequestFeeUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"PerformanceCoefficientsSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"attestationsWeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"blocksWeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"syncWeight","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"PerformanceCoefficientsUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"PerformanceLeewayDataSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"data","type":"tuple[]","indexed":false,"internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"PerformanceLeewayDataUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"QueueConfigSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"priority","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"maxDeposits","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"QueueConfigUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"RewardShareDataSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"data","type":"tuple[]","indexed":false,"internalType":"struct ICSParametersRegistry.KeyNumberValueInterval[]","components":[{"name":"minKeyNumber","type":"uint256","internalType":"uint256"},{"name":"value","type":"uint256","internalType":"uint256"}]}],"anonymous":false},{"type":"event","name":"RewardShareDataUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"StrikesParamsSet","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"lifetime","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"threshold","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"StrikesParamsUnset","inputs":[{"name":"curveId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidAllowedExitDelay","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidKeyNumberValueIntervals","inputs":[]},{"type":"error","name":"InvalidPerformanceCoefficients","inputs":[]},{"type":"error","name":"InvalidPerformanceLeewayData","inputs":[]},{"type":"error","name":"InvalidRewardShareData","inputs":[]},{"type":"error","name":"InvalidStrikesParams","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"QueueCannotBeUsed","inputs":[]},{"type":"error","name":"SafeCastOverflowedUintDowncast","inputs":[{"name":"bits","type":"uint8","internalType":"uint8"},{"name":"value","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroMaxDeposits","inputs":[]},{"type":"error","name":"ZeroQueueLowestPriority","inputs":[]}] diff --git a/interfaces/CSPermissionlessGate.json b/interfaces/CSPermissionlessGate.json index bda444b61..d7e5a5058 100644 --- a/interfaces/CSPermissionlessGate.json +++ b/interfaces/CSPermissionlessGate.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"module","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"CURVE_ID","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"addNodeOperatorETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"type":"function","name":"addNodeOperatorStETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"addNodeOperatorWstETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"error","name":"ZeroModuleAddress","inputs":[]}] +[{"inputs":[{"internalType":"address","name":"module","type":"address"},{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ZeroAdminAddress","type":"error"},{"inputs":[],"name":"ZeroModuleAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CURVE_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE","outputs":[{"internalType":"contract ICSModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVERER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorStETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorWstETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/CSVerifierV2.json b/interfaces/CSVerifierV2.json index 267204b21..ee3bc5f73 100644 --- a/interfaces/CSVerifierV2.json +++ b/interfaces/CSVerifierV2.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"withdrawalAddress","type":"address","internalType":"address"},{"name":"module","type":"address","internalType":"address"},{"name":"slotsPerEpoch","type":"uint64","internalType":"uint64"},{"name":"gindices","type":"tuple","internalType":"struct ICSVerifier.GIndices","components":[{"name":"gIFirstWithdrawalPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstWithdrawalCurr","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstValidatorPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstValidatorCurr","type":"bytes32","internalType":"GIndex"},{"name":"gIHistoricalSummariesPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIHistoricalSummariesCurr","type":"bytes32","internalType":"GIndex"}]},{"name":"firstSupportedSlot","type":"uint64","internalType":"Slot"},{"name":"pivotSlot","type":"uint64","internalType":"Slot"},{"name":"admin","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"BEACON_ROOTS","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"FIRST_SUPPORTED_SLOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"Slot"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_VALIDATOR_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_VALIDATOR_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_WITHDRAWAL_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_WITHDRAWAL_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_HISTORICAL_SUMMARIES_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_HISTORICAL_SUMMARIES_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_INFINITELY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PIVOT_SLOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"Slot"}],"stateMutability":"view"},{"type":"function","name":"RESUME_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"SLOTS_PER_EPOCH","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"WITHDRAWAL_ADDRESS","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getResumeSinceTimestamp","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isPaused","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"pauseFor","inputs":[{"name":"duration","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processHistoricalWithdrawalProof","inputs":[{"name":"beaconBlock","type":"tuple","internalType":"struct ICSVerifier.ProvableBeaconBlockHeader","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"rootsTimestamp","type":"uint64","internalType":"uint64"}]},{"name":"oldBlock","type":"tuple","internalType":"struct ICSVerifier.HistoricalHeaderWitness","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"rootGIndex","type":"bytes32","internalType":"GIndex"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"witness","type":"tuple","internalType":"struct ICSVerifier.WithdrawalWitness","components":[{"name":"withdrawalOffset","type":"uint8","internalType":"uint8"},{"name":"withdrawalIndex","type":"uint64","internalType":"uint64"},{"name":"validatorIndex","type":"uint64","internalType":"uint64"},{"name":"amount","type":"uint64","internalType":"uint64"},{"name":"withdrawalCredentials","type":"bytes32","internalType":"bytes32"},{"name":"effectiveBalance","type":"uint64","internalType":"uint64"},{"name":"slashed","type":"bool","internalType":"bool"},{"name":"activationEligibilityEpoch","type":"uint64","internalType":"uint64"},{"name":"activationEpoch","type":"uint64","internalType":"uint64"},{"name":"exitEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawableEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawalProof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"validatorProof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processWithdrawalProof","inputs":[{"name":"beaconBlock","type":"tuple","internalType":"struct ICSVerifier.ProvableBeaconBlockHeader","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"rootsTimestamp","type":"uint64","internalType":"uint64"}]},{"name":"witness","type":"tuple","internalType":"struct ICSVerifier.WithdrawalWitness","components":[{"name":"withdrawalOffset","type":"uint8","internalType":"uint8"},{"name":"withdrawalIndex","type":"uint64","internalType":"uint64"},{"name":"validatorIndex","type":"uint64","internalType":"uint64"},{"name":"amount","type":"uint64","internalType":"uint64"},{"name":"withdrawalCredentials","type":"bytes32","internalType":"bytes32"},{"name":"effectiveBalance","type":"uint64","internalType":"uint64"},{"name":"slashed","type":"bool","internalType":"bool"},{"name":"activationEligibilityEpoch","type":"uint64","internalType":"uint64"},{"name":"activationEpoch","type":"uint64","internalType":"uint64"},{"name":"exitEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawableEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawalProof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"validatorProof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resume","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Paused","inputs":[{"name":"duration","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Resumed","inputs":[],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"IndexOutOfRange","inputs":[]},{"type":"error","name":"InvalidBlockHeader","inputs":[]},{"type":"error","name":"InvalidChainConfig","inputs":[]},{"type":"error","name":"InvalidGIndex","inputs":[]},{"type":"error","name":"InvalidPivotSlot","inputs":[]},{"type":"error","name":"InvalidWithdrawalAddress","inputs":[]},{"type":"error","name":"PartialWithdrawal","inputs":[]},{"type":"error","name":"PauseUntilMustBeInFuture","inputs":[]},{"type":"error","name":"PausedExpected","inputs":[]},{"type":"error","name":"ResumedExpected","inputs":[]},{"type":"error","name":"RootNotFound","inputs":[]},{"type":"error","name":"UnsupportedSlot","inputs":[{"name":"slot","type":"uint64","internalType":"Slot"}]},{"type":"error","name":"ValidatorNotWithdrawn","inputs":[]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroPauseDuration","inputs":[]},{"type":"error","name":"ZeroWithdrawalAddress","inputs":[]}] +[{"type":"constructor","inputs":[{"name":"withdrawalAddress","type":"address","internalType":"address"},{"name":"module","type":"address","internalType":"address"},{"name":"slotsPerEpoch","type":"uint64","internalType":"uint64"},{"name":"slotsPerHistoricalRoot","type":"uint64","internalType":"uint64"},{"name":"gindices","type":"tuple","internalType":"struct ICSVerifier.GIndices","components":[{"name":"gIFirstWithdrawalPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstWithdrawalCurr","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstValidatorPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstValidatorCurr","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstHistoricalSummaryPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstHistoricalSummaryCurr","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstBlockRootInSummaryPrev","type":"bytes32","internalType":"GIndex"},{"name":"gIFirstBlockRootInSummaryCurr","type":"bytes32","internalType":"GIndex"}]},{"name":"firstSupportedSlot","type":"uint64","internalType":"Slot"},{"name":"pivotSlot","type":"uint64","internalType":"Slot"},{"name":"capellaSlot","type":"uint64","internalType":"Slot"},{"name":"admin","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"BEACON_ROOTS","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"CAPELLA_SLOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"Slot"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"FIRST_SUPPORTED_SLOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"Slot"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_BLOCK_ROOT_IN_SUMMARY_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_BLOCK_ROOT_IN_SUMMARY_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_HISTORICAL_SUMMARY_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_HISTORICAL_SUMMARY_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_VALIDATOR_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_VALIDATOR_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_WITHDRAWAL_CURR","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"GI_FIRST_WITHDRAWAL_PREV","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"GIndex"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_INFINITELY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PIVOT_SLOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"Slot"}],"stateMutability":"view"},{"type":"function","name":"RESUME_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"SLOTS_PER_EPOCH","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"SLOTS_PER_HISTORICAL_ROOT","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"WITHDRAWAL_ADDRESS","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getResumeSinceTimestamp","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isPaused","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"pauseFor","inputs":[{"name":"duration","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processHistoricalWithdrawalProof","inputs":[{"name":"beaconBlock","type":"tuple","internalType":"struct ICSVerifier.ProvableBeaconBlockHeader","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"rootsTimestamp","type":"uint64","internalType":"uint64"}]},{"name":"oldBlock","type":"tuple","internalType":"struct ICSVerifier.HistoricalHeaderWitness","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"witness","type":"tuple","internalType":"struct ICSVerifier.WithdrawalWitness","components":[{"name":"withdrawalOffset","type":"uint8","internalType":"uint8"},{"name":"withdrawalIndex","type":"uint64","internalType":"uint64"},{"name":"validatorIndex","type":"uint64","internalType":"uint64"},{"name":"amount","type":"uint64","internalType":"uint64"},{"name":"withdrawalCredentials","type":"bytes32","internalType":"bytes32"},{"name":"effectiveBalance","type":"uint64","internalType":"uint64"},{"name":"slashed","type":"bool","internalType":"bool"},{"name":"activationEligibilityEpoch","type":"uint64","internalType":"uint64"},{"name":"activationEpoch","type":"uint64","internalType":"uint64"},{"name":"exitEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawableEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawalProof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"validatorProof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"processWithdrawalProof","inputs":[{"name":"beaconBlock","type":"tuple","internalType":"struct ICSVerifier.ProvableBeaconBlockHeader","components":[{"name":"header","type":"tuple","internalType":"struct BeaconBlockHeader","components":[{"name":"slot","type":"uint64","internalType":"Slot"},{"name":"proposerIndex","type":"uint64","internalType":"uint64"},{"name":"parentRoot","type":"bytes32","internalType":"bytes32"},{"name":"stateRoot","type":"bytes32","internalType":"bytes32"},{"name":"bodyRoot","type":"bytes32","internalType":"bytes32"}]},{"name":"rootsTimestamp","type":"uint64","internalType":"uint64"}]},{"name":"witness","type":"tuple","internalType":"struct ICSVerifier.WithdrawalWitness","components":[{"name":"withdrawalOffset","type":"uint8","internalType":"uint8"},{"name":"withdrawalIndex","type":"uint64","internalType":"uint64"},{"name":"validatorIndex","type":"uint64","internalType":"uint64"},{"name":"amount","type":"uint64","internalType":"uint64"},{"name":"withdrawalCredentials","type":"bytes32","internalType":"bytes32"},{"name":"effectiveBalance","type":"uint64","internalType":"uint64"},{"name":"slashed","type":"bool","internalType":"bool"},{"name":"activationEligibilityEpoch","type":"uint64","internalType":"uint64"},{"name":"activationEpoch","type":"uint64","internalType":"uint64"},{"name":"exitEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawableEpoch","type":"uint64","internalType":"uint64"},{"name":"withdrawalProof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"validatorProof","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"keyIndex","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resume","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Paused","inputs":[{"name":"duration","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Resumed","inputs":[],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"IndexOutOfRange","inputs":[]},{"type":"error","name":"InvalidBlockHeader","inputs":[]},{"type":"error","name":"InvalidCapellaSlot","inputs":[]},{"type":"error","name":"InvalidChainConfig","inputs":[]},{"type":"error","name":"InvalidPivotSlot","inputs":[]},{"type":"error","name":"InvalidWithdrawalAddress","inputs":[]},{"type":"error","name":"PartialWithdrawal","inputs":[]},{"type":"error","name":"PauseUntilMustBeInFuture","inputs":[]},{"type":"error","name":"PausedExpected","inputs":[]},{"type":"error","name":"ResumedExpected","inputs":[]},{"type":"error","name":"RootNotFound","inputs":[]},{"type":"error","name":"UnsupportedSlot","inputs":[{"name":"slot","type":"uint64","internalType":"Slot"}]},{"type":"error","name":"ValidatorNotWithdrawn","inputs":[]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroPauseDuration","inputs":[]},{"type":"error","name":"ZeroWithdrawalAddress","inputs":[]}] diff --git a/interfaces/CSVettedGate.json b/interfaces/CSVettedGate.json index 5c966b2ae..c65aac7e9 100644 --- a/interfaces/CSVettedGate.json +++ b/interfaces/CSVettedGate.json @@ -1 +1 @@ -[{"type":"constructor","inputs":[{"name":"module","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ACCOUNTING","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSAccounting"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"END_REFERRAL_SEASON_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MODULE","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ICSModule"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_INFINITELY","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"PAUSE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"RESUME_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"SET_TREE_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"START_REFERRAL_SEASON_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"addNodeOperatorETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"type":"function","name":"addNodeOperatorStETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"addNodeOperatorWstETH","inputs":[{"name":"keysCount","type":"uint256","internalType":"uint256"},{"name":"publicKeys","type":"bytes","internalType":"bytes"},{"name":"signatures","type":"bytes","internalType":"bytes"},{"name":"managementProperties","type":"tuple","internalType":"struct NodeOperatorManagementProperties","components":[{"name":"managerAddress","type":"address","internalType":"address"},{"name":"rewardAddress","type":"address","internalType":"address"},{"name":"extendedManagerPermissions","type":"bool","internalType":"bool"}]},{"name":"permit","type":"tuple","internalType":"struct ICSAccounting.PermitInput","components":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"deadline","type":"uint256","internalType":"uint256"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"claimBondCurve","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"claimReferrerBondCurve","inputs":[{"name":"nodeOperatorId","type":"uint256","internalType":"uint256"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"curveId","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"endCurrentReferralProgramSeason","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getInitializedVersion","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"getReferralsCount","inputs":[{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getResumeSinceTimestamp","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleMember","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getRoleMemberCount","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"hashLeaf","inputs":[{"name":"member","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"pure"},{"type":"function","name":"initialize","inputs":[{"name":"_curveId","type":"uint256","internalType":"uint256"},{"name":"_treeRoot","type":"bytes32","internalType":"bytes32"},{"name":"_treeCid","type":"string","internalType":"string"},{"name":"admin","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"isConsumed","inputs":[{"name":"member","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isPaused","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isReferralProgramSeasonActive","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isReferrerConsumed","inputs":[{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"pauseFor","inputs":[{"name":"duration","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"referralCounts","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"referralCurveId","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"referralProgramSeasonNumber","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"referralsThreshold","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"resume","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setTreeParams","inputs":[{"name":"_treeRoot","type":"bytes32","internalType":"bytes32"},{"name":"_treeCid","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"startNewReferralProgramSeason","inputs":[{"name":"_referralCurveId","type":"uint256","internalType":"uint256"},{"name":"_referralsThreshold","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"treeCid","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"treeRoot","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"verifyProof","inputs":[{"name":"member","type":"address","internalType":"address"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Consumed","inputs":[{"name":"member","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"name":"duration","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ReferralProgramSeasonEnded","inputs":[{"name":"season","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ReferralProgramSeasonStarted","inputs":[{"name":"season","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"referralCurveId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"referralsThreshold","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"ReferrerConsumed","inputs":[{"name":"referrer","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"Resumed","inputs":[],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"TreeSet","inputs":[{"name":"treeRoot","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"treeCid","type":"string","indexed":false,"internalType":"string"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AlreadyConsumed","inputs":[]},{"type":"error","name":"InvalidCurveId","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidProof","inputs":[]},{"type":"error","name":"InvalidReferralsThreshold","inputs":[]},{"type":"error","name":"InvalidTreeCid","inputs":[]},{"type":"error","name":"InvalidTreeRoot","inputs":[]},{"type":"error","name":"NotAllowedToClaim","inputs":[]},{"type":"error","name":"NotEnoughReferrals","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"PauseUntilMustBeInFuture","inputs":[]},{"type":"error","name":"PausedExpected","inputs":[]},{"type":"error","name":"ReferralProgramIsActive","inputs":[]},{"type":"error","name":"ReferralProgramIsNotActive","inputs":[]},{"type":"error","name":"ResumedExpected","inputs":[]},{"type":"error","name":"ZeroAdminAddress","inputs":[]},{"type":"error","name":"ZeroModuleAddress","inputs":[]},{"type":"error","name":"ZeroPauseDuration","inputs":[]}] +[{"inputs":[{"internalType":"address","name":"module","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"AlreadyConsumed","type":"error"},{"inputs":[],"name":"InvalidCurveId","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidReferralsThreshold","type":"error"},{"inputs":[],"name":"InvalidTreeCid","type":"error"},{"inputs":[],"name":"InvalidTreeRoot","type":"error"},{"inputs":[],"name":"NodeOperatorDoesNotExist","type":"error"},{"inputs":[],"name":"NotAllowedToClaim","type":"error"},{"inputs":[],"name":"NotEnoughReferrals","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PauseUntilMustBeInFuture","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[],"name":"ReferralProgramIsActive","type":"error"},{"inputs":[],"name":"ReferralProgramIsNotActive","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[],"name":"ZeroAdminAddress","type":"error"},{"inputs":[],"name":"ZeroModuleAddress","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"}],"name":"Consumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"}],"name":"ReferralProgramSeasonEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referralCurveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referralsThreshold","type":"uint256"}],"name":"ReferralProgramSeasonStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"referralNodeOperatorId","type":"uint256"}],"name":"ReferralRecorded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"}],"name":"ReferrerConsumed","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"treeRoot","type":"bytes32"},{"indexed":false,"internalType":"string","name":"treeCid","type":"string"}],"name":"TreeSet","type":"event"},{"inputs":[],"name":"ACCOUNTING","outputs":[{"internalType":"contract ICSAccounting","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"END_REFERRAL_SEASON_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE","outputs":[{"internalType":"contract ICSModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_INFINITELY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVERER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SET_TREE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_REFERRAL_SEASON_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorStETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"bytes","name":"publicKeys","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"components":[{"internalType":"address","name":"managerAddress","type":"address"},{"internalType":"address","name":"rewardAddress","type":"address"},{"internalType":"bool","name":"extendedManagerPermissions","type":"bool"}],"internalType":"struct NodeOperatorManagementProperties","name":"managementProperties","type":"tuple"},{"components":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ICSAccounting.PermitInput","name":"permit","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"referrer","type":"address"}],"name":"addNodeOperatorWstETH","outputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claimBondCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claimReferrerBondCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"curveId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endCurrentReferralProgramSeason","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getInitializedVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"getReferralsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"season","type":"uint256"}],"name":"getReferralsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getResumeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"hashLeaf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_curveId","type":"uint256"},{"internalType":"bytes32","name":"_treeRoot","type":"bytes32"},{"internalType":"string","name":"_treeCid","type":"string"},{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"isConsumed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isReferralProgramSeasonActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"isReferrerConsumed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"pauseFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"recoverERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"referralCurveId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralProgramSeasonNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralsThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_treeRoot","type":"bytes32"},{"internalType":"string","name":"_treeCid","type":"string"}],"name":"setTreeParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_referralCurveId","type":"uint256"},{"internalType":"uint256","name":"_referralsThreshold","type":"uint256"}],"name":"startNewReferralProgramSeason","outputs":[{"internalType":"uint256","name":"season","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treeCid","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treeRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] diff --git a/interfaces/CuratedSubmitExitRequestHashes.json b/interfaces/CuratedSubmitExitRequestHashes.json new file mode 100644 index 000000000..bebb1abd8 --- /dev/null +++ b/interfaces/CuratedSubmitExitRequestHashes.json @@ -0,0 +1,132 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_nodeOperatorsRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "_stakingRouter", + "type": "address" + }, + { + "internalType": "address", + "name": "_validatorsExitBusOracle", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_creator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_evmScriptCallData", + "type": "bytes" + } + ], + "name": "createEVMScript", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_evmScriptCallData", + "type": "bytes" + } + ], + "name": "decodeEVMScriptCallData", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "moduleId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nodeOpId", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "valIndex", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "valPubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "valPubKeyIndex", + "type": "uint256" + } + ], + "internalType": "struct SubmitExitRequestHashesUtils.ExitRequestInput[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "nodeOperatorsRegistry", + "outputs": [ + { + "internalType": "contract INodeOperatorsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakingRouter", + "outputs": [ + { + "internalType": "contract IStakingRouter", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorsExitBusOracle", + "outputs": [ + { + "internalType": "contract IValidatorsExitBusOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/interfaces/LidoLocator.json b/interfaces/LidoLocator.json index f2145f2d8..5bb321206 100644 --- a/interfaces/LidoLocator.json +++ b/interfaces/LidoLocator.json @@ -1 +1,2 @@ -[{"inputs":[{"components":[{"internalType":"address","name":"accountingOracle","type":"address"},{"internalType":"address","name":"depositSecurityModule","type":"address"},{"internalType":"address","name":"elRewardsVault","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"oracleReportSanityChecker","type":"address"},{"internalType":"address","name":"postTokenRebaseReceiver","type":"address"},{"internalType":"address","name":"burner","type":"address"},{"internalType":"address","name":"stakingRouter","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"validatorsExitBusOracle","type":"address"},{"internalType":"address","name":"withdrawalQueue","type":"address"},{"internalType":"address","name":"withdrawalVault","type":"address"},{"internalType":"address","name":"oracleDaemonConfig","type":"address"}],"internalType":"struct LidoLocator.Config","name":"_config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"accountingOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coreComponents","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositSecurityModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"elRewardsVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legacyOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleDaemonConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleReportComponentsForLido","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleReportSanityChecker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"postTokenRebaseReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsExitBusOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"components":[{"internalType":"address","name":"accountingOracle","type":"address"},{"internalType":"address","name":"depositSecurityModule","type":"address"},{"internalType":"address","name":"elRewardsVault","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"oracleReportSanityChecker","type":"address"},{"internalType":"address","name":"postTokenRebaseReceiver","type":"address"},{"internalType":"address","name":"burner","type":"address"},{"internalType":"address","name":"stakingRouter","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"validatorsExitBusOracle","type":"address"},{"internalType":"address","name":"withdrawalQueue","type":"address"},{"internalType":"address","name":"withdrawalVault","type":"address"},{"internalType":"address","name":"oracleDaemonConfig","type":"address"},{"internalType":"address","name":"validatorExitDelayVerifier","type":"address"},{"internalType":"address","name":"triggerableWithdrawalsGateway","type":"address"}],"internalType":"struct LidoLocator.Config","name":"_config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"accountingOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coreComponents","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositSecurityModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"elRewardsVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legacyOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleDaemonConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleReportComponentsForLido","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleReportSanityChecker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"postTokenRebaseReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"triggerableWithdrawalsGateway","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorExitDelayVerifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsExitBusOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] + diff --git a/interfaces/SDVTSubmitExitRequestHashes.json b/interfaces/SDVTSubmitExitRequestHashes.json new file mode 100644 index 000000000..f25983326 --- /dev/null +++ b/interfaces/SDVTSubmitExitRequestHashes.json @@ -0,0 +1,150 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_trustedCaller", + "type": "address" + }, + { + "internalType": "address", + "name": "_nodeOperatorsRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "_stakingRouter", + "type": "address" + }, + { + "internalType": "address", + "name": "_validatorsExitBusOracle", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_creator", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_evmScriptCallData", + "type": "bytes" + } + ], + "name": "createEVMScript", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_evmScriptCallData", + "type": "bytes" + } + ], + "name": "decodeEVMScriptCallData", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "moduleId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nodeOpId", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "valIndex", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "valPubkey", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "valPubKeyIndex", + "type": "uint256" + } + ], + "internalType": "struct SubmitExitRequestHashesUtils.ExitRequestInput[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "nodeOperatorsRegistry", + "outputs": [ + { + "internalType": "contract INodeOperatorsRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "stakingRouter", + "outputs": [ + { + "internalType": "contract IStakingRouter", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trustedCaller", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validatorsExitBusOracle", + "outputs": [ + { + "internalType": "contract IValidatorsExitBusOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/interfaces/ValidatorsExitBusOracle.json b/interfaces/ValidatorsExitBusOracle.json index 837da4724..ba352a4f1 100644 --- a/interfaces/ValidatorsExitBusOracle.json +++ b/interfaces/ValidatorsExitBusOracle.json @@ -1,1641 +1 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "secondsPerSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "genesisTime", - "type": "uint256" - }, - { - "internalType": "address", - "name": "lidoLocator", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AddressCannotBeSame", - "type": "error" - }, - { - "inputs": [], - "name": "AddressCannotBeZero", - "type": "error" - }, - { - "inputs": [], - "name": "AdminCannotBeZero", - "type": "error" - }, - { - "inputs": [], - "name": "ArgumentOutOfBounds", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "exitDataIndex", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - } - ], - "name": "ExitDataIndexOutOfRange", - "type": "error" - }, - { - "inputs": [], - "name": "ExitHashAlreadySubmitted", - "type": "error" - }, - { - "inputs": [], - "name": "ExitHashNotSubmitted", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "remainingLimit", - "type": "uint256" - } - ], - "name": "ExitRequestsLimitExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "HashCannotBeZero", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "initialRefSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingRefSlot", - "type": "uint256" - } - ], - "name": "InitialRefSlotCannotBeLessThanProcessingOne", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidContractVersionIncrement", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidExitDataIndexSortOrder", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidModuleId", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidRequestsDataLength", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidRequestsDataSortOrder", - "type": "error" - }, - { - "inputs": [], - "name": "LimitExceeded", - "type": "error" - }, - { - "inputs": [], - "name": "NoConsensusReportToProcess", - "type": "error" - }, - { - "inputs": [], - "name": "NonZeroContractVersionOnInit", - "type": "error" - }, - { - "inputs": [], - "name": "PauseUntilMustBeInFuture", - "type": "error" - }, - { - "inputs": [], - "name": "PausedExpected", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "ProcessingDeadlineMissed", - "type": "error" - }, - { - "inputs": [], - "name": "RefSlotAlreadyProcessing", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "prevRefSlot", - "type": "uint256" - } - ], - "name": "RefSlotCannotDecrease", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingRefSlot", - "type": "uint256" - } - ], - "name": "RefSlotMustBeGreaterThanProcessingOne", - "type": "error" - }, - { - "inputs": [], - "name": "RequestsAlreadyDelivered", - "type": "error" - }, - { - "inputs": [], - "name": "RequestsNotDelivered", - "type": "error" - }, - { - "inputs": [], - "name": "ResumedExpected", - "type": "error" - }, - { - "inputs": [], - "name": "SecondsPerSlotCannotBeZero", - "type": "error" - }, - { - "inputs": [], - "name": "SenderIsNotTheConsensusContract", - "type": "error" - }, - { - "inputs": [], - "name": "SenderNotAllowed", - "type": "error" - }, - { - "inputs": [], - "name": "TooLargeExitsPerFrame", - "type": "error" - }, - { - "inputs": [], - "name": "TooLargeFrameDuration", - "type": "error" - }, - { - "inputs": [], - "name": "TooLargeMaxExitRequestsLimit", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxRequestsPerReport", - "type": "uint256" - } - ], - "name": "TooManyExitRequestsInReport", - "type": "error" - }, - { - "inputs": [], - "name": "UnexpectedChainConfig", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "expectedVersion", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "receivedVersion", - "type": "uint256" - } - ], - "name": "UnexpectedConsensusVersion", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "expected", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "received", - "type": "uint256" - } - ], - "name": "UnexpectedContractVersion", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "consensusHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "receivedHash", - "type": "bytes32" - } - ], - "name": "UnexpectedDataHash", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "consensusRefSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dataRefSlot", - "type": "uint256" - } - ], - "name": "UnexpectedRefSlot", - "type": "error" - }, - { - "inputs": [], - "name": "UnexpectedRequestsDataLength", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "format", - "type": "uint256" - } - ], - "name": "UnsupportedRequestsDataFormat", - "type": "error" - }, - { - "inputs": [], - "name": "VersionCannotBeSame", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "name": "ZeroArgument", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroFrameDuration", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroPauseDuration", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "prevAddr", - "type": "address" - } - ], - "name": "ConsensusHashContractSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "version", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "prevVersion", - "type": "uint256" - } - ], - "name": "ConsensusVersionSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "version", - "type": "uint256" - } - ], - "name": "ContractVersionSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes32", - "name": "exitRequestsHash", - "type": "bytes32" - } - ], - "name": "ExitDataProcessing", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "maxExitRequestsLimit", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "exitsPerFrame", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "frameDurationInSec", - "type": "uint256" - } - ], - "name": "ExitRequestsLimitSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "ProcessingStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "ReportDiscarded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "processingDeadlineTime", - "type": "uint256" - } - ], - "name": "ReportSubmitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes32", - "name": "exitRequestsHash", - "type": "bytes32" - } - ], - "name": "RequestsHashSubmitted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "Resumed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } - ], - "name": "RoleAdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleGranted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleRevoked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "stakingModuleId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "nodeOperatorId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "validatorIndex", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "validatorPubkey", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - } - ], - "name": "ValidatorExitRequest", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "requestsProcessed", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - } - ], - "name": "WarnDataIncompleteProcessing", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - } - ], - "name": "WarnProcessingMissed", - "type": "event" - }, - { - "inputs": [], - "name": "DATA_FORMAT_LIST", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "EXIT_REQUEST_LIMIT_MANAGER_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "EXIT_TYPE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "GENESIS_TIME", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MANAGE_CONSENSUS_CONTRACT_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MANAGE_CONSENSUS_VERSION_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "PAUSE_INFINITELY", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "PAUSE_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "RESUME_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "SECONDS_PER_SLOT", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "SUBMIT_DATA_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "SUBMIT_REPORT_HASH_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - } - ], - "name": "discardConsensusReport", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxValidatorsPerReport", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxExitRequestsLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitsPerFrame", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "frameDurationInSec", - "type": "uint256" - } - ], - "name": "finalizeUpgrade_v2", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "getConsensusContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getConsensusReport", - "outputs": [ - { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingDeadlineTime", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "processingStarted", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getConsensusVersion", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getContractVersion", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "exitRequestsHash", - "type": "bytes32" - } - ], - "name": "getDeliveryTimestamp", - "outputs": [ - { - "internalType": "uint256", - "name": "deliveryDateTimestamp", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getExitRequestLimitFullInfo", - "outputs": [ - { - "internalType": "uint256", - "name": "maxExitRequestsLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitsPerFrame", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "frameDurationInSec", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "prevExitRequestsLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "currentExitRequestsLimit", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getLastProcessingRefSlot", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getMaxValidatorsPerReport", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getProcessingState", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "currentFrameRefSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingDeadlineTime", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "dataSubmitted", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "dataFormat", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "requestsSubmitted", - "type": "uint256" - } - ], - "internalType": "struct ValidatorsExitBusOracle.ProcessingState", - "name": "result", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getResumeSinceTimestamp", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], - "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "getRoleMember", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], - "name": "getRoleMemberCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTotalRequestsProcessed", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "internalType": "address", - "name": "consensusContract", - "type": "address" - }, - { - "internalType": "uint256", - "name": "consensusVersion", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "lastProcessingRefSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxValidatorsPerRequest", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxExitRequestsLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitsPerFrame", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "frameDurationInSec", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "isPaused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "pauseFor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pauseUntilInclusive", - "type": "uint256" - } - ], - "name": "pauseUntil", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "resume", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "setConsensusContract", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "version", - "type": "uint256" - } - ], - "name": "setConsensusVersion", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxExitRequestsLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "exitsPerFrame", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "frameDurationInSec", - "type": "uint256" - } - ], - "name": "setExitRequestLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxRequests", - "type": "uint256" - } - ], - "name": "setMaxValidatorsPerReport", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "reportHash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "submitConsensusReport", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "dataFormat", - "type": "uint256" - } - ], - "internalType": "struct ValidatorsExitBus.ExitRequestsData", - "name": "request", - "type": "tuple" - } - ], - "name": "submitExitRequestsData", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "exitRequestsHash", - "type": "bytes32" - } - ], - "name": "submitExitRequestsHash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "consensusVersion", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "refSlot", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "requestsCount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "dataFormat", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct ValidatorsExitBusOracle.ReportData", - "name": "data", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "contractVersion", - "type": "uint256" - } - ], - "name": "submitReportData", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "dataFormat", - "type": "uint256" - } - ], - "internalType": "struct ValidatorsExitBus.ExitRequestsData", - "name": "exitsData", - "type": "tuple" - }, - { - "internalType": "uint256[]", - "name": "exitDataIndexes", - "type": "uint256[]" - }, - { - "internalType": "address", - "name": "refundRecipient", - "type": "address" - } - ], - "name": "triggerExits", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "exitRequests", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "dataFormat", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "unpackExitRequest", - "outputs": [ - { - "internalType": "bytes", - "name": "pubkey", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "nodeOpId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "moduleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "valIndex", - "type": "uint256" - } - ], - "stateMutability": "pure", - "type": "function" - } -] +[{"inputs":[{"internalType":"uint256","name":"secondsPerSlot","type":"uint256"},{"internalType":"uint256","name":"genesisTime","type":"uint256"},{"internalType":"address","name":"lidoLocator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeSame","type":"error"},{"inputs":[],"name":"AddressCannotBeZero","type":"error"},{"inputs":[],"name":"AdminCannotBeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"exitDataIndex","type":"uint256"},{"internalType":"uint256","name":"requestsCount","type":"uint256"}],"name":"ExitDataIndexOutOfRange","type":"error"},{"inputs":[],"name":"ExitHashAlreadySubmitted","type":"error"},{"inputs":[],"name":"ExitHashNotSubmitted","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestsCount","type":"uint256"},{"internalType":"uint256","name":"remainingLimit","type":"uint256"}],"name":"ExitRequestsLimitExceeded","type":"error"},{"inputs":[],"name":"HashCannotBeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"initialRefSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"InitialRefSlotCannotBeLessThanProcessingOne","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidExitDataIndexSortOrder","type":"error"},{"inputs":[],"name":"InvalidModuleId","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"LimitExceeded","type":"error"},{"inputs":[],"name":"NoConsensusReportToProcess","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"PauseUntilMustBeInFuture","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[],"name":"RefSlotAlreadyProcessing","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"prevRefSlot","type":"uint256"}],"name":"RefSlotCannotDecrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotMustBeGreaterThanProcessingOne","type":"error"},{"inputs":[],"name":"RequestsAlreadyDelivered","type":"error"},{"inputs":[],"name":"RequestsNotDelivered","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[],"name":"SecondsPerSlotCannotBeZero","type":"error"},{"inputs":[],"name":"SenderIsNotTheConsensusContract","type":"error"},{"inputs":[],"name":"SenderNotAllowed","type":"error"},{"inputs":[],"name":"TooLargeExitsPerFrame","type":"error"},{"inputs":[],"name":"TooLargeFrameDuration","type":"error"},{"inputs":[],"name":"TooLargeMaxExitRequestsLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestsCount","type":"uint256"},{"internalType":"uint256","name":"maxRequestsPerReport","type":"uint256"}],"name":"TooManyExitRequestsInReport","type":"error"},{"inputs":[],"name":"UnexpectedChainConfig","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedVersion","type":"uint256"},{"internalType":"uint256","name":"receivedVersion","type":"uint256"}],"name":"UnexpectedConsensusVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"bytes32","name":"consensusHash","type":"bytes32"},{"internalType":"bytes32","name":"receivedHash","type":"bytes32"}],"name":"UnexpectedDataHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"consensusRefSlot","type":"uint256"},{"internalType":"uint256","name":"dataRefSlot","type":"uint256"}],"name":"UnexpectedRefSlot","type":"error"},{"inputs":[],"name":"UnexpectedRequestsDataLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"format","type":"uint256"}],"name":"UnsupportedRequestsDataFormat","type":"error"},{"inputs":[],"name":"VersionCannotBeSame","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"ZeroArgument","type":"error"},{"inputs":[],"name":"ZeroFrameDuration","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":true,"internalType":"address","name":"prevAddr","type":"address"}],"name":"ConsensusHashContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"prevVersion","type":"uint256"}],"name":"ConsensusVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"exitRequestsHash","type":"bytes32"}],"name":"ExitDataProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxExitRequestsLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exitsPerFrame","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"frameDurationInSec","type":"uint256"}],"name":"ExitRequestsLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"ProcessingStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"ReportDiscarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"exitRequestsHash","type":"bytes32"}],"name":"RequestsHashSubmitted","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxValidatorsPerReport","type":"uint256"}],"name":"SetMaxValidatorsPerReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"validatorIndex","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"validatorPubkey","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ValidatorExitRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestsProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestsCount","type":"uint256"}],"name":"WarnDataIncompleteProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"WarnProcessingMissed","type":"event"},{"inputs":[],"name":"DATA_FORMAT_LIST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXIT_REQUEST_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXIT_TYPE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENESIS_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_CONSENSUS_CONTRACT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_CONSENSUS_VERSION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_INFINITELY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_PER_SLOT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBMIT_DATA_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBMIT_REPORT_HASH_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"discardConsensusReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxValidatorsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxExitRequestsLimit","type":"uint256"},{"internalType":"uint256","name":"exitsPerFrame","type":"uint256"},{"internalType":"uint256","name":"frameDurationInSec","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConsensusContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConsensusReport","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"},{"internalType":"bool","name":"processingStarted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConsensusVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"exitRequestsHash","type":"bytes32"}],"name":"getDeliveryTimestamp","outputs":[{"internalType":"uint256","name":"deliveryDateTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitRequestLimitFullInfo","outputs":[{"internalType":"uint256","name":"maxExitRequestsLimit","type":"uint256"},{"internalType":"uint256","name":"exitsPerFrame","type":"uint256"},{"internalType":"uint256","name":"frameDurationInSec","type":"uint256"},{"internalType":"uint256","name":"prevExitRequestsLimit","type":"uint256"},{"internalType":"uint256","name":"currentExitRequestsLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxValidatorsPerReport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProcessingState","outputs":[{"components":[{"internalType":"uint256","name":"currentFrameRefSlot","type":"uint256"},{"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bool","name":"dataSubmitted","type":"bool"},{"internalType":"uint256","name":"dataFormat","type":"uint256"},{"internalType":"uint256","name":"requestsCount","type":"uint256"},{"internalType":"uint256","name":"requestsSubmitted","type":"uint256"}],"internalType":"struct ValidatorsExitBusOracle.ProcessingState","name":"result","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getResumeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalRequestsProcessed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","type":"uint256"},{"internalType":"uint256","name":"maxValidatorsPerRequest","type":"uint256"},{"internalType":"uint256","name":"maxExitRequestsLimit","type":"uint256"},{"internalType":"uint256","name":"exitsPerFrame","type":"uint256"},{"internalType":"uint256","name":"frameDurationInSec","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pauseFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pauseUntilInclusive","type":"uint256"}],"name":"pauseUntil","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setConsensusContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"}],"name":"setConsensusVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxExitRequestsLimit","type":"uint256"},{"internalType":"uint256","name":"exitsPerFrame","type":"uint256"},{"internalType":"uint256","name":"frameDurationInSec","type":"uint256"}],"name":"setExitRequestLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxRequests","type":"uint256"}],"name":"setMaxValidatorsPerReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"reportHash","type":"bytes32"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"submitConsensusReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"dataFormat","type":"uint256"}],"internalType":"struct ValidatorsExitBus.ExitRequestsData","name":"request","type":"tuple"}],"name":"submitExitRequestsData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"exitRequestsHash","type":"bytes32"}],"name":"submitExitRequestsHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"requestsCount","type":"uint256"},{"internalType":"uint256","name":"dataFormat","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ValidatorsExitBusOracle.ReportData","name":"data","type":"tuple"},{"internalType":"uint256","name":"contractVersion","type":"uint256"}],"name":"submitReportData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"dataFormat","type":"uint256"}],"internalType":"struct ValidatorsExitBus.ExitRequestsData","name":"exitsData","type":"tuple"},{"internalType":"uint256[]","name":"exitDataIndexes","type":"uint256[]"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"triggerExits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"exitRequests","type":"bytes"},{"internalType":"uint256","name":"dataFormat","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"unpackExitRequest","outputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"uint256","name":"nodeOpId","type":"uint256"},{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256","name":"valIndex","type":"uint256"}],"stateMutability":"pure","type":"function"}] diff --git a/network-config.yaml b/network-config.yaml index 9b15710ad..833a2deb5 100644 --- a/network-config.yaml +++ b/network-config.yaml @@ -2,7 +2,7 @@ live: - name: Ethereum networks: - chainid: 1 - explorer: https://api.etherscan.io/api + explorer: https://api.etherscan.io/v2/api?chainid=1 host: $ETH_RPC_URL id: mainnet multicall2: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696" @@ -34,6 +34,7 @@ development: port: 8545 evm_version: shanghai host: http://127.0.0.1 + explorer: https://api.etherscan.io/v2/api?chainid=1 id: mainnet-fork name: Ganache-CLI (Mainnet Fork) timeout: 360 diff --git a/package.json b/package.json index 0ae436050..374fafcee 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "homepage": "https://mainnet.lido.fi", "dependencies": { "@lido-js/ganache": "=7.9.2-lido", - "hardhat": "^2.24.1", "bignumber.js": "^9.3.0", + "hardhat": "^2.24.1", "tsx": "^4.19.4", "web3": "^4.16.0" } diff --git a/tests/acceptance/test_accounting_oracle.py b/tests/acceptance/test_accounting_oracle.py index 7ada41f4b..919b48287 100644 --- a/tests/acceptance/test_accounting_oracle.py +++ b/tests/acceptance/test_accounting_oracle.py @@ -41,7 +41,7 @@ def test_constants(contract): def test_versioned(contract): - assert contract.getContractVersion() == 2 + assert contract.getContractVersion() == 3 def test_initialize(contract): diff --git a/tests/acceptance/test_accounting_oracle_negative.py b/tests/acceptance/test_accounting_oracle_negative.py index 6f1e47fe8..2e65a9cbc 100644 --- a/tests/acceptance/test_accounting_oracle_negative.py +++ b/tests/acceptance/test_accounting_oracle_negative.py @@ -3,7 +3,7 @@ from web3 import Web3 import pytest -from brownie import ZERO_ADDRESS, Contract, MockHashConsensus, accounts, chain, interface, reverts, chain # type: ignore +from brownie import ZERO_ADDRESS, Contract, MockHashConsensus, accounts, interface, reverts, chain # type: ignore from brownie.network.account import Account from configs.config_mainnet import MAX_ITEMS_PER_EXTRA_DATA_TRANSACTION @@ -15,16 +15,17 @@ ZERO_BYTES32, AccountingReport, oracle_report, - EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_FORMAT_LIST, ) NON_ZERO_HASH = ZERO_HASH[:-1] + b"\x01" FIELDS_WIDTH = ExtraDataLengths + def chain_time_with_offset(offset: int) -> int: return chain.time() + offset + def test_sender_not_allowed(accounting_oracle: Contract, oracle_version: int, stranger: Account) -> None: report = oracle_report(dry_run=True) @@ -180,6 +181,7 @@ def test_setConsensusContract(accounting_oracle: Contract, aragon_agent: Account {"from": aragon_agent}, ) + def test_finalize_upgrade(accounting_oracle: Contract, stranger: Account): with reverts(encode_error("InvalidContractVersionIncrement()")): accounting_oracle.finalizeUpgrade_v2( @@ -192,39 +194,35 @@ def test_finalize_upgrade(accounting_oracle: Contract, stranger: Account): {"from": stranger}, ) + class TestSubmitReportExtraDataList: # TODO: Refactor the test to avoid relying on current operators state assumptions - # The test works on the assumption that there are active keys on the hardcoded + # The test works on the assumption that there are active keys on the hardcoded # operators and will be broken if one of the operators has no active keys def build_extra_data(self, extra_data_items: List[bytes]) -> bytes: return ZERO_BYTES32 + b"".join(extra_data_items) - + def get_nor_operator_exited_keys(self, operator_id: int) -> int: nor = contracts.node_operators_registry - (_,_,_,_,_,exited_keys,_,_) = nor.getNodeOperatorSummary(operator_id) + (_, _, _, _, _, exited_keys, _, _) = nor.getNodeOperatorSummary(operator_id) return exited_keys - def get_nor_operator_stuck_keys(self, operator_id: int) -> int: - nor = contracts.node_operators_registry - (_,_,stuck_keys,_,_,_,_,_) = nor.getNodeOperatorSummary(operator_id) - return stuck_keys - def test_too_short_extra_data_item(self): extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [2])[:36], + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 2, [2], [2])[:36], ] ) - with reverts(encode_error("InvalidExtraDataItem(uint256)", [1])): + (_, _, _, _, _, totalExitedValidators, _, _) = contracts.node_operators_registry.getNodeOperatorSummary(2) + with reverts(encode_error("InvalidExtraDataItem(uint256)", [0])): self.report(extra_data) extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2, 3, 4, 5], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [2]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2, 3, 4, 5], [totalExitedValidators]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 2, [2], [totalExitedValidators]), ] ) @@ -234,50 +232,53 @@ def test_too_short_extra_data_item(self): def test_nos_count_zero(self): extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 2, [], [1]), ] ) - with reverts(encode_error("InvalidExtraDataItem(uint256)", [1])): + with reverts(encode_error("InvalidExtraDataItem(uint256)", [0])): self.report(extra_data) def test_module_id_zero(self): - extra_data = self.build_extra_data( + extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [2]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 0, [2], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 0, [2], [1]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 0, [2], [2]), ] ) - with reverts(encode_error("InvalidExtraDataItem(uint256)", [1])): + with reverts(encode_error("InvalidExtraDataItem(uint256)", [0])): self.report(extra_data) def test_unexpected_extra_data_index(self): extra_data = self.build_extra_data( [ - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), - build_extra_data_item(2, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 2, [2], [1]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2], [1]), + build_extra_data_item(2, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 2, [2], [1]), ] ) with reverts(encode_error("UnexpectedExtraDataIndex(uint256,uint256)", [0, 1])): self.report(extra_data) + totalExitedValidators = self.get_nor_operator_exited_keys(2) + extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), - build_extra_data_item(3, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2], [totalExitedValidators]), + build_extra_data_item(3, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2], [totalExitedValidators]), ] ) with reverts(encode_error("UnexpectedExtraDataIndex(uint256,uint256)", [1, 3])): self.report(extra_data) - extra_data = self.build_extra_data( + totalExitedValidators = self.get_nor_operator_exited_keys(2) + + extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, 1, [2], [1]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2], [totalExitedValidators]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, 1, [2], [totalExitedValidators]), ] ) @@ -298,13 +299,15 @@ def test_unsupported_extra_data_type(self): def test_invalid_extra_data_sort_order_on_same_items(self): module_id = 1 operator_id = 2 - current_stuck_keys = self.get_nor_operator_stuck_keys(operator_id) - new_stuck_keys = current_stuck_keys + 1 + current_exited_keys = self.get_nor_operator_exited_keys(operator_id) + new_exited_keys = current_exited_keys + 1 extra_data = self.build_extra_data( [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, module_id, [operator_id], [new_stuck_keys]), - build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, module_id, [operator_id], [new_stuck_keys]), + build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, module_id, [operator_id], + [new_exited_keys]), + build_extra_data_item(1, ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, module_id, [operator_id], + [new_exited_keys]), ] ) @@ -326,21 +329,6 @@ def test_invalid_extra_data_sort_order_on_same_operator(self): with reverts(encode_error("InvalidExtraDataSortOrder(uint256)", [1])): self.report(extra_data) - def test_invalid_extra_data_sort_order_on_stuck(self): - module_id = 1 - unsorted_operator_ids = [1, 3, 2] - current_stuck_keys = [self.get_nor_operator_stuck_keys(operator_id) for operator_id in unsorted_operator_ids] - new_stuck_keys = [keys + 1 for keys in current_stuck_keys] - - extra_data = self.build_extra_data( - [ - build_extra_data_item(0, ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, module_id, unsorted_operator_ids, new_stuck_keys), - ] - ) - - with reverts(encode_error("InvalidExtraDataSortOrder(uint256)", [0])): - self.report(extra_data) - def test_invalid_extra_data_sort_order_on_exited(self): module_id = 1 unsorted_operator_ids = [33, 35, 34] @@ -357,16 +345,18 @@ def test_invalid_extra_data_sort_order_on_exited(self): self.report(extra_data) def test_unexpected_extra_data_item(self, extra_data_service: ExtraDataService) -> None: - module_id = 1 - stuck_keys_operator_id = 38 - exited_keys_operator_id = 33 - - current_stuck_keys = self.get_nor_operator_stuck_keys(stuck_keys_operator_id) - current_exited_keys = self.get_nor_operator_exited_keys(exited_keys_operator_id) - extra_data = extra_data_service.collect( - {(module_id, stuck_keys_operator_id): current_stuck_keys + 1}, - {(module_id, exited_keys_operator_id): current_exited_keys + 1}, + { + (1, 2): self.get_nor_operator_exited_keys(2) + 1, + (1, 3): self.get_nor_operator_exited_keys(3) + 1, + (1, 4): self.get_nor_operator_exited_keys(4) + 1, + (1, 5): self.get_nor_operator_exited_keys(5) + 1, + (1, 6): self.get_nor_operator_exited_keys(6) + 1, + (1, 7): self.get_nor_operator_exited_keys(7) + 1, + (1, 8): self.get_nor_operator_exited_keys(8) + 1, + (1, 9): self.get_nor_operator_exited_keys(9) + 1, + (1, 10): self.get_nor_operator_exited_keys(10) + 1, + }, MAX_ITEMS_PER_EXTRA_DATA_TRANSACTION, 1, ) @@ -375,8 +365,8 @@ def test_unexpected_extra_data_item(self, extra_data_service: ExtraDataService) encode_error( "UnexpectedExtraDataItemsCount(uint256,uint256)", [ - extra_data.items_count - 1, - extra_data.items_count, + extra_data.items_count - 1, # expected count + extra_data.items_count - 1, # index of the item that makes the count mismatch ], ) ): @@ -392,14 +382,11 @@ def test_already_processed( extra_data_service: ExtraDataService, ): module_id = 1 - stuck_keys_operator_id = 38 exited_keys_operator_id = 33 - current_stuck_keys = self.get_nor_operator_stuck_keys(stuck_keys_operator_id) current_exited_keys = self.get_nor_operator_exited_keys(exited_keys_operator_id) extra_data = extra_data_service.collect( - {(module_id, stuck_keys_operator_id): current_stuck_keys + 1}, {(module_id, exited_keys_operator_id): current_exited_keys + 1}, MAX_ITEMS_PER_EXTRA_DATA_TRANSACTION, 1, @@ -753,6 +740,6 @@ def build_extra_data_item( module_id.to_bytes(FIELDS_WIDTH.MODULE_ID, **opts), len(nos_ids).to_bytes(FIELDS_WIDTH.NODE_OPS_COUNT, **opts), b"".join(i.to_bytes(FIELDS_WIDTH.NODE_OPERATOR_IDS, **opts) for i in nos_ids), - b"".join(i.to_bytes(FIELDS_WIDTH.STUCK_OR_EXITED_VALS_COUNT, **opts) for i in vals_count), + b"".join(i.to_bytes(FIELDS_WIDTH.EXITED_VALS_COUNT, **opts) for i in vals_count), ) ) diff --git a/tests/acceptance/test_csm.py b/tests/acceptance/test_csm.py index ca33c1cef..861750918 100644 --- a/tests/acceptance/test_csm.py +++ b/tests/acceptance/test_csm.py @@ -24,8 +24,11 @@ CS_ORACLE_EPOCHS_PER_FRAME, ORACLE_QUORUM, ORACLE_COMMITTEE, + CS_PARAMS_REGISTRY_ADDRESS, + CS_EXIT_PENALTIES_ADDRESS, + CS_STRIKES_ADDRESS, + CS_EJECTOR_ADDRESS ) -from utils.test.helpers import ETH contracts: ContractsLazyLoader = contracts @@ -38,61 +41,104 @@ def _str_to_bytes32(s: str) -> str: def csm(): return contracts.csm -@pytest.fixture(scope="module") -def early_adoption(): - return contracts.cs_early_adoption @pytest.fixture(scope="module") def fee_distributor(): return contracts.cs_fee_distributor + @pytest.fixture(scope="module") def fee_oracle(): return contracts.cs_fee_oracle + @pytest.fixture(scope="module") def hash_consensus(): return contracts.csm_hash_consensus + @pytest.fixture(scope="module") def accounting(): return contracts.cs_accounting + @pytest.fixture(scope="module") def verifier(): return contracts.cs_verifier +@pytest.fixture(scope="module") +def permissionless_gate(): + return contracts.cs_permissionless_gate + + +@pytest.fixture(scope="module") +def vetted_gate(): + return contracts.cs_vetted_gate + + +@pytest.fixture(scope="module") +def parameters_registry(): + return contracts.cs_parameters_registry + + +@pytest.fixture(scope="module") +def ejector(): + return contracts.cs_ejector + + +@pytest.fixture(scope="module") +def strikes(): + return contracts.cs_strikes + + +@pytest.fixture(scope="module") +def exit_penalties(): + return contracts.cs_exit_penalties + + @pytest.fixture(scope="module") def lido(): return interface.Lido(LIDO) -def test_proxy(csm, accounting, fee_distributor, fee_oracle): + +def test_proxy( + csm, + accounting, + fee_distributor, + fee_oracle, + vetted_gate, + strikes, + exit_penalties, +): assert interface.OssifiableProxy(csm).proxy__getAdmin() == contracts.agent.address assert interface.OssifiableProxy(accounting).proxy__getAdmin() == contracts.agent.address assert interface.OssifiableProxy(fee_distributor).proxy__getAdmin() == contracts.agent.address assert interface.OssifiableProxy(fee_oracle).proxy__getAdmin() == contracts.agent.address + assert interface.OssifiableProxy(vetted_gate).proxy__getAdmin() == contracts.agent.address + assert interface.OssifiableProxy(strikes).proxy__getAdmin() == contracts.agent.address + assert interface.OssifiableProxy(exit_penalties).proxy__getAdmin() == contracts.agent.address class TestCSM: def test_init_state(self, csm): assert csm.getType() == _str_to_bytes32("community-onchain-v1") assert csm.LIDO_LOCATOR() == LIDO_LOCATOR - assert csm.accounting() == CS_ACCOUNTING_ADDRESS - assert csm.keyRemovalCharge() == 0 # Updated from 0.02 to 0 in vote 2025/07/16 + assert csm.PARAMETERS_REGISTRY() == CS_PARAMS_REGISTRY_ADDRESS + assert csm.ACCOUNTING() == CS_ACCOUNTING_ADDRESS + assert csm.EXIT_PENALTIES() == CS_EXIT_PENALTIES_ADDRESS assert not csm.isPaused() - assert csm.publicRelease() class TestAccounting: def test_initial_state(self, accounting): - assert accounting.CSM() == CSM_ADDRESS + assert accounting.MODULE() == CSM_ADDRESS assert accounting.LIDO_LOCATOR() == LIDO_LOCATOR assert accounting.LIDO() == LIDO assert accounting.WITHDRAWAL_QUEUE() == WITHDRAWAL_QUEUE assert accounting.WSTETH() == WSTETH_TOKEN - assert accounting.feeDistributor() == CS_FEE_DISTRIBUTOR_ADDRESS + assert accounting.FEE_DISTRIBUTOR() == CS_FEE_DISTRIBUTOR_ADDRESS assert accounting.chargePenaltyRecipient() == AGENT assert not accounting.isPaused() @@ -102,12 +148,14 @@ def test_allowances(self, lido): assert lido.allowance(CS_ACCOUNTING_ADDRESS, WITHDRAWAL_QUEUE) == uin256_max assert lido.allowance(CS_ACCOUNTING_ADDRESS, BURNER) == uin256_max + class TestFeeDistributor: def test_initial_state(self, fee_distributor): assert fee_distributor.STETH() == LIDO assert fee_distributor.ACCOUNTING() == CS_ACCOUNTING_ADDRESS assert fee_distributor.ORACLE() == CS_FEE_ORACLE_ADDRESS + assert fee_distributor.rebateRecipient() == AGENT class TestFeeOracle: @@ -115,13 +163,14 @@ class TestFeeOracle: def test_initial_state(self, fee_oracle): assert fee_oracle.SECONDS_PER_SLOT() == CHAIN_SECONDS_PER_SLOT assert fee_oracle.GENESIS_TIME() == CHAIN_GENESIS_TIME - assert fee_oracle.feeDistributor() == CS_FEE_DISTRIBUTOR_ADDRESS - assert fee_oracle.getContractVersion() == 1 + assert fee_oracle.FEE_DISTRIBUTOR() == CS_FEE_DISTRIBUTOR_ADDRESS + assert fee_oracle.STRIKES() == CS_STRIKES_ADDRESS + assert fee_oracle.getContractVersion() == 2 assert fee_oracle.getConsensusContract() == CS_ORACLE_HASH_CONSENSUS_ADDRESS - assert fee_oracle.getConsensusVersion() == 2 - assert fee_oracle.avgPerfLeewayBP() == 500 + assert fee_oracle.getConsensusVersion() == 3 assert not fee_oracle.isPaused() + class TestHashConsensus: def test_initial_state(self, hash_consensus): @@ -131,35 +180,69 @@ def test_initial_state(self, hash_consensus): assert chain_config["genesisTime"] == CHAIN_GENESIS_TIME frame_config = hash_consensus.getFrameConfig() - assert frame_config["initialEpoch"] >= 326715 + assert frame_config["initialEpoch"] == 326715 assert frame_config["epochsPerFrame"] == CS_ORACLE_EPOCHS_PER_FRAME assert frame_config["fastLaneLengthSlots"] == 1800 assert hash_consensus.getQuorum() == ORACLE_QUORUM - assert hash_consensus.getInitialRefSlot() >= 326715 * CHAIN_SLOTS_PER_EPOCH - 1 + assert hash_consensus.getInitialRefSlot() == 10454879 members = hash_consensus.getMembers() assert sorted(members["addresses"]) == sorted(ORACLE_COMMITTEE) assert hash_consensus.getReportProcessor() == CS_FEE_ORACLE_ADDRESS -def test_early_adoption_state(early_adoption): - assert early_adoption.MODULE() == CSM_ADDRESS - assert early_adoption.CURVE_ID() == 1 + +def test_permissionless_gate_state(permissionless_gate): + assert permissionless_gate.MODULE() == CSM_ADDRESS + assert permissionless_gate.CURVE_ID() == 0 + + +def test_vetted_gate_state(vetted_gate): + assert vetted_gate.MODULE() == CSM_ADDRESS + assert vetted_gate.curveId() == 2 + + +def test_ejector_state(ejector): + assert ejector.MODULE() == CSM_ADDRESS + assert ejector.STRIKES() == CS_STRIKES_ADDRESS + assert ejector.STAKING_MODULE_ID() == 3 + + +def test_strikes_state(strikes): + assert strikes.MODULE() == CSM_ADDRESS + assert strikes.EXIT_PENALTIES() == CS_EXIT_PENALTIES_ADDRESS + assert strikes.ORACLE() == CS_FEE_ORACLE_ADDRESS + assert strikes.PARAMETERS_REGISTRY() == CS_PARAMS_REGISTRY_ADDRESS + assert strikes.ejector() == CS_EJECTOR_ADDRESS + + +def test_exit_penalties_state(exit_penalties): + assert exit_penalties.MODULE() == CSM_ADDRESS + assert exit_penalties.PARAMETERS_REGISTRY() == CS_PARAMS_REGISTRY_ADDRESS + assert exit_penalties.STRIKES() == CS_STRIKES_ADDRESS + + +def test_parameters_registry_state(parameters_registry): + assert parameters_registry.QUEUE_LOWEST_PRIORITY() == 5 + assert parameters_registry.QUEUE_LEGACY_PRIORITY() == 4 + def test_verifier_state(verifier): assert verifier.WITHDRAWAL_ADDRESS() == WITHDRAWAL_VAULT assert verifier.MODULE() == CSM_ADDRESS assert verifier.SLOTS_PER_EPOCH() == CHAIN_SLOTS_PER_EPOCH - with reverts(): # The new CS Verifier (vote 2025/07/16) doesn't have these 2 methods - verifier.GI_HISTORICAL_SUMMARIES_PREV() - verifier.GI_HISTORICAL_SUMMARIES_CURR() - - assert verifier.GI_FIRST_WITHDRAWAL_PREV() == HexString("0x0000000000000000000000000000000000000000000000000000000000e1c004", "bytes") + assert verifier.GI_FIRST_WITHDRAWAL_PREV() == HexString("0x000000000000000000000000000000000000000000000000000000000161c004", "bytes") assert verifier.GI_FIRST_WITHDRAWAL_CURR() == HexString("0x000000000000000000000000000000000000000000000000000000000161c004", "bytes") - assert verifier.GI_FIRST_VALIDATOR_PREV() == HexString("0x0000000000000000000000000000000000000000000000000056000000000028", "bytes") + assert verifier.GI_FIRST_VALIDATOR_PREV() == HexString("0x0000000000000000000000000000000000000000000000000096000000000028", "bytes") assert verifier.GI_FIRST_VALIDATOR_CURR() == HexString("0x0000000000000000000000000000000000000000000000000096000000000028", "bytes") - assert verifier.FIRST_SUPPORTED_SLOT() == 8626176 - assert verifier.PIVOT_SLOT() == 11649024 + assert verifier.GI_FIRST_HISTORICAL_SUMMARY_PREV() == HexString("0x000000000000000000000000000000000000000000000000000000b600000018", "bytes") + assert verifier.GI_FIRST_HISTORICAL_SUMMARY_CURR() == HexString("0x000000000000000000000000000000000000000000000000000000b600000018", "bytes") + assert verifier.GI_FIRST_BLOCK_ROOT_IN_SUMMARY_PREV() == HexString("0x000000000000000000000000000000000000000000000000000000000040000d", "bytes") + assert verifier.GI_FIRST_BLOCK_ROOT_IN_SUMMARY_CURR() == HexString("0x000000000000000000000000000000000000000000000000000000000040000d", "bytes") + + assert verifier.FIRST_SUPPORTED_SLOT() == 364032 * CHAIN_SLOTS_PER_EPOCH + assert verifier.PIVOT_SLOT() == verifier.FIRST_SUPPORTED_SLOT() + assert verifier.CAPELLA_SLOT() == 194048 * CHAIN_SLOTS_PER_EPOCH diff --git a/tests/acceptance/test_gate_seal_acceptance.py b/tests/acceptance/test_gate_seal_acceptance.py index dcb71b502..df9f2af99 100644 --- a/tests/acceptance/test_gate_seal_acceptance.py +++ b/tests/acceptance/test_gate_seal_acceptance.py @@ -2,7 +2,8 @@ from brownie import Contract, interface, web3 # type: ignore from brownie.network.account import Account -from utils.config import GATE_SEAL_EXPIRY_TIMESTAMP, GATE_SEAL_PAUSE_DURATION, contracts, GATE_SEAL, GATE_SEAL_COMMITTEE +from utils.config import GATE_SEAL_EXPIRY_TIMESTAMP, GATE_SEAL_PAUSE_DURATION, contracts, GATE_SEAL, \ + GATE_SEAL_COMMITTEE, RESEAL_MANAGER, VEB_TWG_GATE_SEAL @pytest.fixture(scope="module") @@ -15,23 +16,59 @@ def contract() -> Contract: return interface.GateSeal(GATE_SEAL) -def test_gate_seal(contract: Contract, gate_seal_committee: Account): +@pytest.fixture(scope="module") +def veb_twg_contract() -> Contract: + return interface.GateSeal(VEB_TWG_GATE_SEAL) + + +@pytest.fixture(scope="module") +def reseal_manager() -> Contract: + return interface.ResealManager(RESEAL_MANAGER) + + +def test_gate_seal(contract: Contract, gate_seal_committee: Account, reseal_manager: Contract): assert contract.get_sealing_committee() == gate_seal_committee sealables = contract.get_sealables() - assert len(sealables) == 2 - assert contracts.validators_exit_bus_oracle.address in sealables + assert len(sealables) == 1 assert contracts.withdrawal_queue.address in sealables - _check_role(contracts.validators_exit_bus_oracle, "PAUSE_ROLE", contract.address) - _check_role(contracts.withdrawal_queue, "PAUSE_ROLE", contract.address) + _check_role(contracts.withdrawal_queue, "PAUSE_ROLE", reseal_manager.address) assert contract.get_seal_duration_seconds() == GATE_SEAL_PAUSE_DURATION assert contract.get_expiry_timestamp() == GATE_SEAL_EXPIRY_TIMESTAMP assert not contract.is_expired() -def _check_role(contract: Contract, role: str, holder: str): +def test_veb_twg_gate_seal(veb_twg_contract: Contract, gate_seal_committee: Account, reseal_manager: Contract): + assert veb_twg_contract.get_sealing_committee() == gate_seal_committee + + sealables = veb_twg_contract.get_sealables() + assert len(sealables) == 2 + assert contracts.validators_exit_bus_oracle.address in sealables + assert contracts.triggerable_withdrawals_gateway.address in sealables + + role = "PAUSE_ROLE" + role_bytes = web3.keccak(text=role).hex() + + assert contracts.validators_exit_bus_oracle.getRoleMemberCount(role_bytes) == 2, f"Role {role} on {contracts.validators_exit_bus_oracle.address} should have exactly two holders" + assert contracts.validators_exit_bus_oracle.getRoleMember(role_bytes, 0) == reseal_manager.address, f"Role {role} holder on {contracts.validators_exit_bus_oracle.address} should be {reseal_manager.address}" + assert contracts.validators_exit_bus_oracle.getRoleMember(role_bytes, 1) == veb_twg_contract.address, f"Role {role} holder on {contracts.validators_exit_bus_oracle.address} should be {contracts.veb_twg_contract.address}" + + assert contracts.triggerable_withdrawals_gateway.getRoleMemberCount(role_bytes) == 2, f"Role {role} on {contracts.triggerable_withdrawals_gateway.address} should have exactly two holders" + assert contracts.triggerable_withdrawals_gateway.getRoleMember(role_bytes, 0) == veb_twg_contract.address, f"Role {role} holder on {contracts.triggerable_withdrawals_gateway.address} should be {contracts.veb_twg_contract.address}" + assert contracts.triggerable_withdrawals_gateway.getRoleMember(role_bytes, 1) == reseal_manager.address, f"Role {role} holder on {contracts.triggerable_withdrawals_gateway.address} should be {reseal_manager.address}" + + assert veb_twg_contract.get_seal_duration_seconds() == GATE_SEAL_PAUSE_DURATION + assert veb_twg_contract.get_expiry_timestamp() == GATE_SEAL_EXPIRY_TIMESTAMP + assert not veb_twg_contract.is_expired() + + + _check_role(contracts.validators_exit_bus_oracle, "RESUME_ROLE", reseal_manager.address, 1) + _check_role(contracts.triggerable_withdrawals_gateway, "RESUME_ROLE", reseal_manager.address, 1) + + +def _check_role(contract: Contract, role: str, holder: str, holders_count: int = 2): role_bytes = web3.keccak(text=role).hex() - assert contract.getRoleMemberCount(role_bytes) == 2, f"Role {role} on {contract} should have exactly two holders" + assert contract.getRoleMemberCount(role_bytes) == holders_count, f"Role {role} on {contract} should have exactly '{holders_count}' holders" assert contract.getRoleMember(role_bytes, 0) == holder, f"Role {role} holder on {contract} should be {holder}" diff --git a/tests/acceptance/test_lido.py b/tests/acceptance/test_lido.py index 91090167e..0ac485621 100644 --- a/tests/acceptance/test_lido.py +++ b/tests/acceptance/test_lido.py @@ -80,7 +80,7 @@ def test_steth(contract): assert contract.getTotalShares() > contract.sharesOf(INITIAL_DEAD_TOKEN_HOLDER) # unlimited allowance for burner to burn shares from withdrawal queue assert contract.allowance(contracts.withdrawal_queue, contracts.burner) == 2**256 - 1 - assert contract.allowance(contracts.node_operators_registry, contracts.burner) == 2**256 - 1 + assert contract.allowance(contracts.node_operators_registry, contracts.burner) == 0 def test_lido_state(contract): @@ -88,7 +88,7 @@ def test_lido_state(contract): modules = contracts.staking_router.getStakingModules() total_exited_validators = sum( - contracts.staking_router.getStakingModuleSummary(module[0])[0] + contracts.staking_router.getStakingModuleSummary(module[0])[0] for module in modules ) diff --git a/tests/acceptance/test_node_operators_registry.py b/tests/acceptance/test_node_operators_registry.py index e695f99ee..aea5d7069 100644 --- a/tests/acceptance/test_node_operators_registry.py +++ b/tests/acceptance/test_node_operators_registry.py @@ -4,6 +4,7 @@ from utils.config import ( contracts, NODE_OPERATORS_REGISTRY, + NOR_EXIT_DEADLINE_IN_SEC, NODE_OPERATORS_REGISTRY_IMPL, NODE_OPERATORS_REGISTRY_ARAGON_APP_ID, NODE_OPERATORS_REGISTRY_VERSION, @@ -55,21 +56,15 @@ def test_initialize(contract): contract.initialize( contracts.lido_locator, CURATED_STAKING_MODULE_TYPE, - CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY, + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) def test_finalize_upgrade(contract): with reverts("UNEXPECTED_CONTRACT_VERSION"): - contract.finalizeUpgrade_v2( - contracts.lido_locator, - CURATED_STAKING_MODULE_TYPE, - CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY, - {"from": contracts.voting}, - ) - with reverts("UNEXPECTED_CONTRACT_VERSION"): - contract.finalizeUpgrade_v3( + contract.finalizeUpgrade_v4( + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) @@ -80,21 +75,12 @@ def test_petrified(): contract.initialize( contracts.lido_locator, CURATED_STAKING_MODULE_TYPE, - CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY, + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) with reverts("CONTRACT_NOT_INITIALIZED"): - contract.finalizeUpgrade_v2( - contracts.lido_locator, - CURATED_STAKING_MODULE_TYPE, - CURATED_STAKING_MODULE_STUCK_PENALTY_DELAY, - {"from": contracts.voting}, - ) - with reverts("CONTRACT_NOT_INITIALIZED"): - contract.finalizeUpgrade_v3( - {"from": contracts.voting}, - ) + contract.finalizeUpgrade_v4(NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}) def test_nor_state(contract): diff --git a/tests/acceptance/test_oracle_daemon_config.py b/tests/acceptance/test_oracle_daemon_config.py index 32183a60f..bbb52536d 100644 --- a/tests/acceptance/test_oracle_daemon_config.py +++ b/tests/acceptance/test_oracle_daemon_config.py @@ -7,11 +7,9 @@ NORMALIZED_CL_REWARD_MISTAKE_RATE_BP, REBASE_CHECK_NEAREST_EPOCH_DISTANCE, REBASE_CHECK_DISTANT_EPOCH_DISTANCE, - VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS, - VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS, + EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS, PREDICTION_DURATION_IN_SLOTS, FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT, - NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP, ) @@ -20,11 +18,9 @@ "NORMALIZED_CL_REWARD_MISTAKE_RATE_BP": NORMALIZED_CL_REWARD_MISTAKE_RATE_BP, "REBASE_CHECK_NEAREST_EPOCH_DISTANCE": REBASE_CHECK_NEAREST_EPOCH_DISTANCE, "REBASE_CHECK_DISTANT_EPOCH_DISTANCE": REBASE_CHECK_DISTANT_EPOCH_DISTANCE, - "VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS": VALIDATOR_DELAYED_TIMEOUT_IN_SLOTS, - "VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS": VALIDATOR_DELINQUENT_TIMEOUT_IN_SLOTS, "PREDICTION_DURATION_IN_SLOTS": PREDICTION_DURATION_IN_SLOTS, "FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT": FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT, - "NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP": NODE_OPERATOR_NETWORK_PENETRATION_THRESHOLD_BP, + "EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS": EXIT_EVENTS_LOOKBACK_WINDOW_IN_SLOTS, } diff --git a/tests/acceptance/test_simple_dvt_module.py b/tests/acceptance/test_simple_dvt_module.py index d6d69986c..a2a7e75a0 100644 --- a/tests/acceptance/test_simple_dvt_module.py +++ b/tests/acceptance/test_simple_dvt_module.py @@ -9,6 +9,7 @@ SIMPLE_DVT_ARAGON_APP_ID, SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY, SIMPLE_DVT_MODULE_TYPE, + NOR_EXIT_DEADLINE_IN_SEC, EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, EASYTRACK_EVMSCRIPT_EXECUTOR, EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY, @@ -21,7 +22,6 @@ EASYTRACK_SIMPLE_DVT_CHANGE_NODE_OPERATOR_MANAGERS_FACTORY, ) - REQUEST_BURN_SHARES_ROLE = "0x4be29e0e4eb91f98f709d98803cba271592782e293b84a625e025cbb40197ba8" STAKING_ROUTER_ROLE = "0xbb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6" MANAGE_NODE_OPERATOR_ROLE = "0x78523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f8" @@ -63,17 +63,15 @@ def test_initialize(contract): contract.initialize( contracts.lido_locator, SIMPLE_DVT_MODULE_TYPE, - SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY, + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) def test_finalize_upgrade(contract): with reverts("UNEXPECTED_CONTRACT_VERSION"): - contract.finalizeUpgrade_v2( - contracts.lido_locator, - SIMPLE_DVT_MODULE_TYPE, - SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY, + contract.finalizeUpgrade_v4( + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) @@ -84,15 +82,13 @@ def test_petrified(): contract.initialize( contracts.lido_locator, SIMPLE_DVT_MODULE_TYPE, - SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY, + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) with reverts("CONTRACT_NOT_INITIALIZED"): - contract.finalizeUpgrade_v2( - contracts.lido_locator, - SIMPLE_DVT_MODULE_TYPE, - SIMPLE_DVT_MODULE_STUCK_PENALTY_DELAY, + contract.finalizeUpgrade_v4( + NOR_EXIT_DEADLINE_IN_SEC, {"from": contracts.voting}, ) @@ -178,7 +174,6 @@ def test_simple_dvt_permissions(contract): def test_simple_dvt_easytrack(contract): - easy_track = contracts.easy_track add_node_operators_evm_script_factory = EASYTRACK_SIMPLE_DVT_ADD_NODE_OPERATORS_FACTORY diff --git a/tests/acceptance/test_staking_router.py b/tests/acceptance/test_staking_router.py index f4f091816..9a5da1d5a 100644 --- a/tests/acceptance/test_staking_router.py +++ b/tests/acceptance/test_staking_router.py @@ -72,12 +72,9 @@ def test_initialize(contract): def test_finalize_upgrade(contract): with reverts(encode_error( "UnexpectedContractVersion(uint256,uint256)", - [2, 1], + [3, 2], )): - contract.finalizeUpgrade_v2( - [10_000, 10_000], - [50, 50], - [25, 25], + contract.finalizeUpgrade_v3( {"from": contracts.voting}, ) diff --git a/tests/acceptance/test_veb_negative.py b/tests/acceptance/test_veb_negative.py index b96a53cf4..c690d36dc 100644 --- a/tests/acceptance/test_veb_negative.py +++ b/tests/acceptance/test_veb_negative.py @@ -30,14 +30,6 @@ def ref_slot(): return ref_slot -def test_get_last_requested_validator_indices(contract): - with reverts(): # ArgumentOutOfBounds() - contract.getLastRequestedValidatorIndices(2**24 + 1, []) - - with reverts(): # ArgumentOutOfBounds() - contract.getLastRequestedValidatorIndices(1, [2**40 + 1]) - - def test_submit_report_data_checks(contract, ref_slot, stranger): contract_version = contract.getContractVersion() consensus_version = contract.getConsensusVersion() @@ -216,71 +208,7 @@ def test_handle_consensus_report_data_wrong_module_id(contract, ref_slot): contracts.hash_consensus_for_validators_exit_bus_oracle, ) - with reverts(encode_error("InvalidRequestsData()")): - contract.submitReportData(report, contract_version, {"from": submitter}) - - -def test_handle_consensus_report_data_second_exit(contract, ref_slot): - unreachable_cl_validator_index = 100_000_000 - no_global_index = (module_id, no_id) = (1, 33) - validator_key = contracts.node_operators_registry.getSigningKey(no_id, 1)[0] - - # set validator index to the next one to avoid NodeOpValidatorIndexMustIncrease error - validator = LidoValidator(index=unreachable_cl_validator_index, pubkey=validator_key) - - contract_version = contract.getContractVersion() - consensus_version = contract.getConsensusVersion() - - data, data_format = encode_data([(no_global_index, validator)]) - report = ( - consensus_version, - ref_slot, - len([(no_global_index, validator)]), - data_format, - data, - ) - report_data = encode_data_from_abi(report, contracts.validators_exit_bus_oracle.abi, "submitReportData") - report_hash = web3.keccak(report_data) - submitter = reach_consensus( - ref_slot, - report_hash, - consensus_version, - contracts.hash_consensus_for_validators_exit_bus_oracle, - ) - - contract.submitReportData(report, contract_version, {"from": submitter}) - - wait_to_next_available_report_time(contracts.hash_consensus_for_validators_exit_bus_oracle) - ref_slot, _ = contracts.hash_consensus_for_validators_exit_bus_oracle.getCurrentFrame() - - data, data_format = encode_data([(no_global_index, validator)]) - report = ( - consensus_version, - ref_slot, - len([(no_global_index, validator)]), - data_format, - data, - ) - report_data = encode_data_from_abi(report, contracts.validators_exit_bus_oracle.abi, "submitReportData") - report_hash = web3.keccak(report_data) - submitter = reach_consensus( - ref_slot, - report_hash, - consensus_version, - contracts.hash_consensus_for_validators_exit_bus_oracle, - ) - - with reverts( - encode_error( - "NodeOpValidatorIndexMustIncrease(uint256,uint256,uint256,uint256)", - ( - module_id, - no_id, - unreachable_cl_validator_index, - unreachable_cl_validator_index, - ), - ) - ): + with reverts(encode_error("InvalidModuleId()")): contract.submitReportData(report, contract_version, {"from": submitter}) diff --git a/tests/acceptance/test_veb_oracle.py b/tests/acceptance/test_veb_oracle.py index 1d44bd631..232c5afcb 100644 --- a/tests/acceptance/test_veb_oracle.py +++ b/tests/acceptance/test_veb_oracle.py @@ -14,6 +14,10 @@ VEBO_EPOCHS_PER_FRAME, VEBO_FAST_LANE_LENGTH_SLOTS, ORACLE_QUORUM, + MAX_VALIDATORS_PER_REPORT, + MAX_EXIT_REQUESTS_LIMIT, + EXITS_PER_FRAME, + FRAME_DURATION_IN_SEC, VEBO_CONSENSUS_VERSION, ) from utils.evm_script import encode_error @@ -38,7 +42,7 @@ def test_immutables(contract): def test_versioned(contract): - assert contract.getContractVersion() == 1 + assert contract.getContractVersion() == 2 def test_initialize(contract): @@ -48,6 +52,10 @@ def test_initialize(contract): HASH_CONSENSUS_FOR_AO, 1, 1, + MAX_VALIDATORS_PER_REPORT, + MAX_EXIT_REQUESTS_LIMIT, + EXITS_PER_FRAME, + FRAME_DURATION_IN_SEC, {"from": contracts.voting}, ) @@ -60,6 +68,10 @@ def test_petrified(contract): HASH_CONSENSUS_FOR_AO, 1, 1, + MAX_VALIDATORS_PER_REPORT, + MAX_EXIT_REQUESTS_LIMIT, + EXITS_PER_FRAME, + FRAME_DURATION_IN_SEC, {"from": contracts.voting}, ) diff --git a/tests/acceptance/test_withdrawal_vault.py b/tests/acceptance/test_withdrawal_vault.py index e496280e1..8e6bb120e 100644 --- a/tests/acceptance/test_withdrawal_vault.py +++ b/tests/acceptance/test_withdrawal_vault.py @@ -17,17 +17,18 @@ def test_proxy(contract): def test_versioned(contract): - assert contract.getContractVersion() == 1 + assert contract.getContractVersion() == 2 def test_initialize(contract): - with reverts(encode_error("NonZeroContractVersionOnInit()")): + with reverts(encode_error("UnexpectedContractVersion(uint256,uint256)", (2, 0))): contract.initialize({"from": contracts.voting}) def test_petrified(): + dummy_version = 115792089237316195423570985008687907853269984665640564039457584007913129639935 impl = interface.WithdrawalVault(WITHDRAWAL_VAULT_IMPL) - with reverts(encode_error("NonZeroContractVersionOnInit()")): + with reverts(encode_error("UnexpectedContractVersion(uint256,uint256)", (dummy_version, 0))): impl.initialize({"from": contracts.voting}) @@ -36,3 +37,5 @@ def test_withdrawals_vault(contract): assert contract.TREASURY() == contracts.agent assert contract.LIDO() == contracts.lido_locator.lido() assert contract.TREASURY() == contracts.lido_locator.treasury() + assert contract.TRIGGERABLE_WITHDRAWALS_GATEWAY() == contracts.triggerable_withdrawals_gateway.address + assert contract.TRIGGERABLE_WITHDRAWALS_GATEWAY() == contracts.lido_locator.triggerableWithdrawalsGateway() diff --git a/tests/conftest.py b/tests/conftest.py index f1bcda034..6453db18d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -153,7 +153,7 @@ def execute_votes(accounts, vote_ids, dao_voting, topup="10 ether"): print(f"vote #{vote_id} executed") execution_transactions.append(tx) - Helpers._prefetch_contracts_from_etherscan() + Helpers.prefetch_contracts_from_etherscan() return execution_transactions @@ -163,13 +163,14 @@ def is_executed(vote_id, dao_voting): return vote_status[1] @staticmethod - def _prefetch_contracts_from_etherscan(): + def prefetch_contracts_from_etherscan(): if not Helpers._etherscan_is_fetched: print(f"prefetch contracts from Etherscan to parse events") # In case of issue with events parsing from local abi # add contracts here to fetch the abis from etherscan # Use next format to fetch the abi: # Contract.from_explorer() + Contract.from_explorer(contracts.cs_exit_penalties.address) Helpers._etherscan_is_fetched = True diff --git a/tests/regression/test_csm.py b/tests/regression/test_csm.py index 2b69d294a..a16bcf854 100644 --- a/tests/regression/test_csm.py +++ b/tests/regression/test_csm.py @@ -1,18 +1,26 @@ import pytest -from brownie import reverts, web3, ZERO_ADDRESS, accounts +from brownie import reverts, web3, ZERO_ADDRESS, accounts, chain +from tests.conftest import Helpers from utils.balance import set_balance_in_wei from utils.config import ( contracts, ContractsLazyLoader, + CSM_COMMITTEE_MS, + EASYTRACK_CSM_SETTLE_EL_REWARDS_STEALING_PENALTY_FACTORY, + EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY, ) from utils.dsm import UnvetArgs, to_bytes, set_single_guardian -from utils.evm_script import encode_error from utils.staking_module import calc_module_reward_shares -from utils.test.csm_helpers import csm_add_node_operator, get_ea_member, csm_upload_keys, get_ea_members +from utils.test.csm_helpers import ( + csm_add_node_operator, csm_upload_keys, csm_add_ics_node_operator, + csm_set_ics_tree_members, +) from utils.test.deposits_helpers import fill_deposit_buffer +from utils.test.easy_track_helpers import _encode_calldata from utils.test.helpers import ETH +from utils.test.merkle_tree import StrikesTree from utils.test.oracle_report_helpers import ( oracle_report, wait_to_next_available_report_time, @@ -31,16 +39,36 @@ MAX_DEPOSITS = 50 +@pytest.fixture(scope="module", autouse=True) +def prefetch_contracts_from_etherscan(): + Helpers.prefetch_contracts_from_etherscan() + + @pytest.fixture(scope="module") def csm(): return contracts.csm +@pytest.fixture(scope="module") +def permissionless_gate(): + return contracts.cs_permissionless_gate + + +@pytest.fixture(scope="module") +def vetted_gate(): + return contracts.cs_vetted_gate + + @pytest.fixture(scope="module") def accounting(): return contracts.cs_accounting +@pytest.fixture(scope="module") +def parameters_registry(): + return contracts.cs_parameters_registry + + @pytest.fixture(scope="module") def fee_distributor(): return contracts.cs_fee_distributor @@ -52,14 +80,38 @@ def fee_oracle(): @pytest.fixture(scope="module") -def early_adoption(): - return contracts.cs_early_adoption +def ejector(): + return contracts.cs_ejector + + +@pytest.fixture(scope="module") +def strikes(): + return contracts.cs_strikes @pytest.fixture -def node_operator(csm, accounting) -> int: - address, proof = get_ea_member() - return csm_add_node_operator(csm, accounting, address, proof) +def depositable_node_operator(csm, accounting, permissionless_gate, stranger): + increase_staking_module_share(module_id=CSM_MODULE_ID, share_multiplier=2) + csm.cleanDepositQueue(2 * csm.getNonce(), {"from": stranger.address}) + for queue_priority in range(0, 6): + deposit_batch = csm.depositQueueItem(queue_priority, csm.depositQueuePointers(queue_priority)["head"]) + if deposit_batch: + node_operator_id = (deposit_batch >> 192) & ((1 << 64) - 1) + keys_count = (deposit_batch >> 128) & ((1 << 64) - 1) + break + else: + address = accounts[7].address + keys_count = 5 + node_operator_id = csm_add_node_operator(csm, permissionless_gate, accounting, address, keys_count=keys_count) + return node_operator_id, keys_count + + +@pytest.fixture +def node_operator(depositable_node_operator, csm, accounting) -> int: + node_operator, keys_count = depositable_node_operator + fill_deposit_buffer(keys_count) + contracts.lido.deposit(keys_count, CSM_MODULE_ID, "0x", {"from": contracts.deposit_security_module}) + return node_operator @pytest.fixture @@ -78,15 +130,6 @@ def remove_stake_limit(): contracts.lido.removeStakingLimit({"from": accounts.at(contracts.agent, force=True)}) -@pytest.fixture -def deposits_to_csm(csm, pause_modules, node_operator, remove_stake_limit): - (_, _, depositable) = csm.getStakingModuleSummary() - fill_deposit_buffer(depositable) - increase_staking_module_share(module_id=CSM_MODULE_ID, share_multiplier=2) - for i in range(0, depositable, MAX_DEPOSITS): - contracts.lido.deposit(MAX_DEPOSITS, CSM_MODULE_ID, "0x", {"from": contracts.deposit_security_module}) - - @pytest.fixture def ref_slot(): wait_to_next_available_report_time(contracts.csm_hash_consensus) @@ -97,14 +140,15 @@ def ref_slot(): def distribute_reward_tree(node_operator, ref_slot): consensus_version = contracts.cs_fee_oracle.getConsensusVersion() oracle_version = contracts.cs_fee_oracle.getContractVersion() - claimable_shares = contracts.cs_fee_distributor.totalClaimableShares() + distributed_before = contracts.lido.sharesOf(contracts.cs_fee_distributor) + claimed_before = contracts.cs_fee_distributor.distributedShares(node_operator) rewards = ETH(0.05) oracle_report(cl_diff=rewards) - distributed_shares = contracts.lido.sharesOf(contracts.cs_fee_distributor) - claimable_shares + distributed_shares = contracts.lido.sharesOf(contracts.cs_fee_distributor) - distributed_before assert distributed_shares > 0 - report, report_hash, tree = prepare_csm_report({node_operator: distributed_shares}, ref_slot) + report, report_hash, tree = prepare_csm_report({node_operator: claimed_before + distributed_shares}, ref_slot, distributed_shares) submitter = reach_consensus( ref_slot, @@ -114,22 +158,34 @@ def distribute_reward_tree(node_operator, ref_slot): ) contracts.cs_fee_oracle.submitReportData(report, oracle_version, {"from": submitter}) - return tree + return distributed_shares, tree.tree -@pytest.mark.parametrize("address, proof", get_ea_members()) -def test_add_ea_node_operator(csm, accounting, early_adoption, address, proof): - no_id = csm_add_node_operator(csm, accounting, address, proof) - no = csm.getNodeOperator(no_id) +def get_sys_fee_to_eject(): + withdrawal_request_sys_address = '0x00000961Ef480Eb55e80D19ad83579A64c007002' + val = web3.eth.call({ + "to": withdrawal_request_sys_address, + "data": "0x", + }) + return int.from_bytes(val, "big") - assert no["managerAddress"] == address - assert no["rewardAddress"] == address - assert accounting.getBondCurveId(no_id) == early_adoption.CURVE_ID() +def test_add_node_operators_ics(csm, vetted_gate, accounting, accounts): + members = [account.address for account in accounts[3:5]] + tree = csm_set_ics_tree_members(members) + for address in members: + proof = list(tree.tree.get_proof(tree.tree.find(tree.tree.leaf([address])))) + no_id = csm_add_ics_node_operator(csm, vetted_gate, accounting, address, proof) + no = csm.getNodeOperator(no_id) -def test_add_node_operator_permissionless(csm, accounting, accounts): + assert no["managerAddress"] == address + assert no["rewardAddress"] == address + assert accounting.getBondCurveId(no_id) == vetted_gate.curveId() + + +def test_add_node_operator_permissionless(csm, permissionless_gate, accounting, accounts): address = accounts[8].address - no_id = csm_add_node_operator(csm, accounting, address, proof=[]) + no_id = csm_add_node_operator(csm, permissionless_gate, accounting, address) no = csm.getNodeOperator(no_id) assert no["managerAddress"] == address @@ -137,49 +193,17 @@ def test_add_node_operator_permissionless(csm, accounting, accounts): assert accounting.getBondCurveId(no_id) == accounting.DEFAULT_BOND_CURVE_ID() -def test_add_node_operator_keys_more_than_limit(csm, accounting): - address, proof = get_ea_member() - keys_count = csm.MAX_SIGNING_KEYS_PER_OPERATOR_BEFORE_PUBLIC_RELEASE() + 1 - no_id = csm_add_node_operator(csm, accounting, address, proof, keys_count=keys_count) - no = csm.getNodeOperator(no_id) - - assert no["totalAddedKeys"] == keys_count - - -def test_add_node_operator_permissionless_keys_more_than_limit(csm, accounting, accounts): - keys_count = csm.MAX_SIGNING_KEYS_PER_OPERATOR_BEFORE_PUBLIC_RELEASE() + 1 - address = accounts[8].address - no_id = csm_add_node_operator(csm, accounting, address, proof=[], keys_count=keys_count) - no = csm.getNodeOperator(no_id) - - assert no["totalAddedKeys"] == keys_count - - -def test_upload_keys_more_than_limit(csm, accounting, node_operator): - no = csm.getNodeOperator(node_operator) - keys_before = no["totalAddedKeys"] - keys_count = csm.MAX_SIGNING_KEYS_PER_OPERATOR_BEFORE_PUBLIC_RELEASE() - keys_before + 1 - csm_upload_keys(csm, accounting, node_operator, keys_count) - - no = csm.getNodeOperator(node_operator) - assert no["totalAddedKeys"] == keys_count + keys_before - - @pytest.mark.usefixtures("pause_modules") -def test_deposit(node_operator, csm, remove_stake_limit): - (_, _, depositable_validators_count) = csm.getStakingModuleSummary() - deposits_count = depositable_validators_count - fill_deposit_buffer(deposits_count) - increase_staking_module_share(module_id=CSM_MODULE_ID, share_multiplier=2) - - for i in range(0, deposits_count, MAX_DEPOSITS): - contracts.lido.deposit(MAX_DEPOSITS, CSM_MODULE_ID, "0x", {"from": contracts.deposit_security_module}) +def test_deposit(depositable_node_operator, csm, remove_stake_limit): + (node_operator, keys_count) = depositable_node_operator + fill_deposit_buffer(keys_count) + total_deposited_before = csm.getNodeOperator(node_operator)["totalDepositedKeys"] + contracts.lido.deposit(keys_count, CSM_MODULE_ID, "0x", {"from": contracts.deposit_security_module}) no = csm.getNodeOperator(node_operator) - assert no["totalDepositedKeys"] == no["totalAddedKeys"] + assert no["totalDepositedKeys"] == total_deposited_before + keys_count -@pytest.mark.usefixtures("deposits_to_csm") def test_mint_rewards_happy_path(csm, fee_distributor): csm_shares_before = contracts.lido.sharesOf(csm) fee_distributor_shares_before = contracts.lido.sharesOf(fee_distributor) @@ -203,19 +227,10 @@ def test_csm_target_limits(csm, node_operator): assert no["targetLimit"] == target_limit -def test_csm_update_refunded(node_operator): - refunded_validators_count = 1 - with reverts(encode_error("NotSupported()")): - contracts.staking_router.updateRefundedValidatorsCount( - CSM_MODULE_ID, node_operator, refunded_validators_count, {"from": contracts.agent} - ) - - -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_report_exited(csm, node_operator, extra_data_service): total_exited = csm.getStakingModuleSummary()["totalExitedValidators"] exited_keys = 5 - extra_data = extra_data_service.collect({}, {(CSM_MODULE_ID, node_operator): exited_keys}, exited_keys, exited_keys) + extra_data = extra_data_service.collect({(CSM_MODULE_ID, node_operator): exited_keys}, exited_keys, exited_keys) oracle_report( extraDataFormat=1, extraDataHashList=extra_data.extra_data_hash_list, @@ -229,25 +244,6 @@ def test_csm_report_exited(csm, node_operator, extra_data_service): assert no["totalExitedKeys"] == exited_keys -@pytest.mark.usefixtures("deposits_to_csm") -def test_csm_report_stuck(csm, node_operator, extra_data_service): - total_exited = csm.getStakingModuleSummary()["totalExitedValidators"] - stuck_keys = 5 - extra_data = extra_data_service.collect({(CSM_MODULE_ID, node_operator): stuck_keys}, {}, stuck_keys, stuck_keys) - oracle_report( - extraDataFormat=1, - extraDataHashList=extra_data.extra_data_hash_list, - extraDataItemsCount=1, - extraDataList=extra_data.extra_data_list, - stakingModuleIdsWithNewlyExitedValidators=[CSM_MODULE_ID], - numExitedValidatorsByStakingModule=[total_exited], - ) - - no = csm.getNodeOperator(node_operator) - assert no["stuckValidatorsCount"] == stuck_keys - - -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_get_staking_module_summary(csm, accounting, node_operator, extra_data_service, remove_stake_limit): (exited_before, deposited_before, depositable_before) = contracts.staking_router.getStakingModuleSummary( CSM_MODULE_ID @@ -255,7 +251,7 @@ def test_csm_get_staking_module_summary(csm, accounting, node_operator, extra_da # Assure there are new exited keys exited_keys = 5 - extra_data = extra_data_service.collect({}, {(CSM_MODULE_ID, node_operator): exited_keys}, exited_keys, exited_keys) + extra_data = extra_data_service.collect({(CSM_MODULE_ID, node_operator): exited_keys}, exited_keys, exited_keys) oracle_report( extraDataFormat=1, extraDataHashList=extra_data.extra_data_hash_list, @@ -283,36 +279,38 @@ def test_csm_get_staking_module_summary(csm, accounting, node_operator, extra_da assert depositable_after == depositable_before + new_depositable -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_get_node_operator_summary(csm, node_operator, extra_data_service): total_exited = csm.getStakingModuleSummary()["totalExitedValidators"] no = csm.getNodeOperator(node_operator) - exited_keys = 1 - stuck_keys = 1 + exited_keys = no["totalExitedKeys"] + 1 extra_data = extra_data_service.collect( - {(CSM_MODULE_ID, node_operator): stuck_keys}, {(CSM_MODULE_ID, node_operator): exited_keys}, 2, 2 + {(CSM_MODULE_ID, node_operator): exited_keys}, exited_keys, exited_keys ) oracle_report( extraDataFormat=1, extraDataHashList=extra_data.extra_data_hash_list, - extraDataItemsCount=2, + extraDataItemsCount=1, extraDataList=extra_data.extra_data_list, stakingModuleIdsWithNewlyExitedValidators=[CSM_MODULE_ID], numExitedValidatorsByStakingModule=[total_exited], ) summary = contracts.staking_router.getNodeOperatorSummary(CSM_MODULE_ID, node_operator) - assert summary["targetLimitMode"] == 0 - assert summary["targetValidatorsCount"] == 0 - assert summary["stuckValidatorsCount"] == stuck_keys + assert summary["targetLimitMode"] == no["targetLimitMode"] + assert summary["targetValidatorsCount"] == no["targetLimit"] + # DEPRECATED # + assert summary["stuckValidatorsCount"] == 0 assert summary["refundedValidatorsCount"] == 0 assert summary["stuckPenaltyEndTimestamp"] == 0 + ############## assert summary["totalExitedValidators"] == exited_keys assert summary["totalDepositedValidators"] == no["totalDepositedKeys"] - assert summary["depositableValidatorsCount"] == 0 + assert summary["depositableValidatorsCount"] == no["depositableValidatorsCount"] -def test_csm_decrease_vetted_keys(csm, node_operator, stranger): +def test_csm_decrease_vetted_keys(csm, depositable_node_operator, stranger): + (node_operator, keys_count) = depositable_node_operator + total_added_keys = csm.getNodeOperator(node_operator)["totalAddedKeys"] block_number = web3.eth.get_block_number() block = web3.eth.get_block(block_number) staking_module_nonce = contracts.staking_router.getStakingModuleNonce(CSM_MODULE_ID) @@ -322,7 +320,7 @@ def test_csm_decrease_vetted_keys(csm, node_operator, stranger): staking_module_id=CSM_MODULE_ID, nonce=staking_module_nonce, node_operator_ids=to_bytes(node_operator, 16), - vetted_signing_keys_counts=to_bytes(1, 32), + vetted_signing_keys_counts=to_bytes(total_added_keys - keys_count, 32), ) set_single_guardian(contracts.deposit_security_module, contracts.agent, stranger) @@ -330,30 +328,28 @@ def test_csm_decrease_vetted_keys(csm, node_operator, stranger): contracts.deposit_security_module.unvetSigningKeys(*unvet_args.to_tuple(), (0, 0), {"from": stranger.address}) no = csm.getNodeOperator(node_operator) - assert no["totalVettedKeys"] == 1 + assert no["totalVettedKeys"] == total_added_keys - keys_count -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_penalize_node_operator(csm, accounting, node_operator, helpers): bond_shares_before = accounting.getBondShares(node_operator) - tx = csm.submitInitialSlashing(node_operator, 0, {"from": contracts.cs_verifier}) + withdrawal_info = (node_operator, 0, ETH(30)) + tx = csm.submitWithdrawals([withdrawal_info], {"from": contracts.cs_verifier}) assert "StETHBurnRequested" in tx.events burnt_shares = tx.events["StETHBurnRequested"]["amountOfShares"] assert accounting.getBondShares(node_operator) == bond_shares_before - burnt_shares -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_eth_bond(csm, accounting, node_operator): manager_address = csm.getNodeOperator(node_operator)["managerAddress"] set_balance_in_wei(manager_address, ETH(2)) bond_shares_before = accounting.getBondShares(node_operator) shares = contracts.lido.getSharesByPooledEth(ETH(1)) - csm.depositETH(node_operator, {"from": manager_address, "value": ETH(1)}) + accounting.depositETH(node_operator, {"from": manager_address, "value": ETH(1)}) assert accounting.getBondShares(node_operator) == bond_shares_before + shares -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_steth_bond(csm, accounting, node_operator): manager_address = csm.getNodeOperator(node_operator)["managerAddress"] set_balance_in_wei(manager_address, ETH(2)) @@ -363,11 +359,10 @@ def test_csm_steth_bond(csm, accounting, node_operator): contracts.lido.approve(accounting, ETH(2), {"from": manager_address}) shares = contracts.lido.getSharesByPooledEth(ETH(1)) - csm.depositStETH(node_operator, ETH(1), (0, 0, 0, 0, 0), {"from": manager_address}) + accounting.depositStETH(node_operator, ETH(1), (0, 0, 0, 0, 0), {"from": manager_address}) assert accounting.getBondShares(node_operator) == bond_shares_before + shares -@pytest.mark.usefixtures("deposits_to_csm") def test_csm_wsteth_bond(csm, accounting, node_operator): manager_address = csm.getNodeOperator(node_operator)["managerAddress"] set_balance_in_wei(manager_address, ETH(2)) @@ -380,64 +375,206 @@ def test_csm_wsteth_bond(csm, accounting, node_operator): contracts.wsteth.getStETHByWstETH(contracts.wsteth.balanceOf(manager_address)) ) bond_shares_before = accounting.getBondShares(node_operator) - csm.depositWstETH( + accounting.depositWstETH( node_operator, contracts.wsteth.balanceOf(manager_address), (0, 0, 0, 0, 0), {"from": manager_address} ) assert accounting.getBondShares(node_operator) == bond_shares_before + shares -@pytest.mark.usefixtures("deposits_to_csm") -def test_csm_claim_rewards_steth(csm, node_operator, ref_slot): +def test_csm_claim_rewards_steth(csm, accounting, node_operator, ref_slot): reward_address = csm.getNodeOperator(node_operator)["rewardAddress"] shares_before = contracts.lido.sharesOf(reward_address) - accounting_shares_before = contracts.lido.sharesOf(contracts.cs_accounting) - tree = distribute_reward_tree(node_operator, ref_slot).tree - shares = tree.values[0]["value"][1] - proof = list(tree.get_proof(tree.find(tree.leaf((node_operator, shares))))) + distributed_shares, tree = distribute_reward_tree(node_operator, ref_slot) + cumulative_shares = tree.values[0]["value"][1] + proof = list(tree.get_proof(tree.find(tree.leaf((node_operator, cumulative_shares))))) + claimable_bond_shares_before = accounting.getClaimableBondShares(node_operator) + + accounting.claimRewardsStETH(node_operator, ETH(999), cumulative_shares, proof, {"from": reward_address}) - csm.claimRewardsStETH(node_operator, ETH(1), shares, proof, {"from": reward_address}) shares_after = contracts.lido.sharesOf(reward_address) - accounting_shares_after = contracts.lido.sharesOf(contracts.cs_accounting) - assert shares_after == shares_before + (accounting_shares_before + shares - accounting_shares_after) + assert shares_after == shares_before + distributed_shares + claimable_bond_shares_before -@pytest.mark.usefixtures("deposits_to_csm") -def test_csm_claim_rewards_wsteth(csm, node_operator, ref_slot): - tree = distribute_reward_tree(node_operator, ref_slot).tree +def test_csm_claim_rewards_wsteth(csm, accounting, node_operator, ref_slot): + _, tree = distribute_reward_tree(node_operator, ref_slot) shares = tree.values[0]["value"][1] proof = list(tree.get_proof(tree.find(tree.leaf((node_operator, shares))))) reward_address = csm.getNodeOperator(node_operator)["rewardAddress"] wsteth_before = contracts.wsteth.balanceOf(reward_address) - csm.claimRewardsWstETH(node_operator, ETH(1), shares, proof, {"from": reward_address}) + accounting.claimRewardsWstETH(node_operator, ETH(1), shares, proof, {"from": reward_address}) assert contracts.wsteth.balanceOf(reward_address) > wsteth_before -@pytest.mark.usefixtures("deposits_to_csm") -def test_csm_claim_rewards_eth(csm, node_operator, ref_slot): - tree = distribute_reward_tree(node_operator, ref_slot).tree +def test_csm_claim_rewards_eth(csm, accounting, node_operator, ref_slot): + _, tree = distribute_reward_tree(node_operator, ref_slot) shares = tree.values[0]["value"][1] proof = list(tree.get_proof(tree.find(tree.leaf((node_operator, shares))))) reward_address = csm.getNodeOperator(node_operator)["rewardAddress"] withdrawal_requests = contracts.withdrawal_queue.getWithdrawalRequests(reward_address) - csm.claimRewardsUnstETH(node_operator, ETH(1), shares, proof, {"from": reward_address}) + accounting.claimRewardsUnstETH(node_operator, ETH(1), shares, proof, {"from": reward_address}) assert len(contracts.withdrawal_queue.getWithdrawalRequests(reward_address)) == len(withdrawal_requests) + 1 -def test_csm_remove_key(csm, node_operator): +def test_csm_remove_key(csm, parameters_registry, accounting, node_operator): + csm_upload_keys(csm, accounting, node_operator, 1) + no = csm.getNodeOperator(node_operator) keys_before = no["totalAddedKeys"] manager_address = csm.getNodeOperator(node_operator)["managerAddress"] - tx = csm.removeKeys(node_operator, 0, 1, {"from": manager_address}) - assert "KeyRemovalChargeApplied" not in tx.events - assert "BondCharged" not in tx.events - charge_amount = contracts.lido.getPooledEthByShares( - contracts.lido.getSharesByPooledEth(csm.keyRemovalCharge()) - ) + tx = csm.removeKeys(node_operator, keys_before - 1, 1, {"from": manager_address}) + + assert "KeyRemovalChargeApplied" in tx.events + assert "BondCharged" in tx.events - assert charge_amount == 0 # keyRemovalCharge is zero since vote 2025/07/16 + curve_id = accounting.getBondCurveId(node_operator) + expected_charge_amount = contracts.lido.getPooledEthByShares( + contracts.lido.getSharesByPooledEth(parameters_registry.getKeyRemovalCharge(curve_id)) + ) + assert tx.events["BondCharged"]["toChargeAmount"] == expected_charge_amount no = csm.getNodeOperator(node_operator) assert no["totalAddedKeys"] == keys_before - 1 + + +def test_eject_bad_performer(csm, accounting, ejector, strikes, node_operator, stranger): + index_to_eject = 0 + pubkey_to_eject = csm.getSigningKeys(node_operator, index_to_eject, 1) + leaf_to_eject = (node_operator, pubkey_to_eject, [1, 1, 1, 1, 1, 1]) + another_pubkey = csm.getSigningKeys(node_operator, index_to_eject + 1, 1) + strikes_tree = StrikesTree.new( + [leaf_to_eject, (node_operator, another_pubkey, [1, 1, 0, 0, 0, 0])] + ) + index_in_tree = strikes_tree.tree.find(strikes_tree.tree.leaf(leaf_to_eject)) + proof, flags = strikes_tree.tree.get_multi_proof([index_in_tree]) + strikes.processOracleReport( + strikes_tree.root, + "QmTest123456789", + {"from": contracts.cs_fee_oracle} + ) + + eject_payment_value = get_sys_fee_to_eject() + + bad_performer = (node_operator, index_to_eject, [1, 1, 1, 1, 1, 1]) + tx = strikes.processBadPerformanceProof( + [bad_performer], + proof, + flags, + ZERO_ADDRESS, + {"value": eject_payment_value, "from": stranger} + ) + assert "StrikesPenaltyProcessed" in tx.events + assert tx.events["StrikesPenaltyProcessed"]["nodeOperatorId"] == node_operator + assert tx.events["StrikesPenaltyProcessed"]["pubkey"] == pubkey_to_eject + + curve_id = accounting.getBondCurveId(node_operator) + penalty = contracts.cs_parameters_registry.getBadPerformancePenalty(curve_id) + assert tx.events["StrikesPenaltyProcessed"]["strikesPenalty"] == penalty + + assert "TriggeredExitFeeRecorded" in tx.events + assert tx.events["TriggeredExitFeeRecorded"]["nodeOperatorId"] == node_operator + assert tx.events["TriggeredExitFeeRecorded"]["pubkey"] == pubkey_to_eject + assert tx.events["TriggeredExitFeeRecorded"]["exitType"] == 1 + assert tx.events["TriggeredExitFeeRecorded"]["withdrawalRequestPaidFee"] == eject_payment_value + assert tx.events["TriggeredExitFeeRecorded"]["withdrawalRequestRecordedFee"] == eject_payment_value + + +def test_voluntary_eject(csm, ejector, node_operator): + eject_payment_value = get_sys_fee_to_eject() + operator_address = csm.getNodeOperatorOwner(node_operator) + + tx = ejector.voluntaryEject( + node_operator, 0, 1, ZERO_ADDRESS, {"value": eject_payment_value, "from": operator_address} + ) + assert "TriggeredExitFeeRecorded" not in tx.events + + +def test_report_validator_exit_delay(csm, accounting, parameters_registry, node_operator): + pubkey = csm.getSigningKeys(node_operator, 0, 1) + day_in_seconds = 60 * 60 * 24 + + tx = csm.reportValidatorExitDelay(node_operator, 0, pubkey, 7 * day_in_seconds, {"from": contracts.staking_router}) + assert "ValidatorExitDelayProcessed" in tx.events + assert tx.events["ValidatorExitDelayProcessed"]["nodeOperatorId"] == node_operator + assert tx.events["ValidatorExitDelayProcessed"]["pubkey"] == pubkey + + curve_id = accounting.getBondCurveId(node_operator) + penalty = parameters_registry.getExitDelayPenalty(curve_id) + assert tx.events["ValidatorExitDelayProcessed"]["delayPenalty"] == penalty + + +def test_on_validator_exit_triggered(csm, node_operator): + eject_payment_value = 1 + pubkey = csm.getSigningKeys(node_operator, 0, 1) + exit_type = 3 + + tx = csm.onValidatorExitTriggered(node_operator, pubkey, 1, exit_type, {"from": contracts.staking_router}) + assert "TriggeredExitFeeRecorded" in tx.events + assert tx.events["TriggeredExitFeeRecorded"]["nodeOperatorId"] == node_operator + assert tx.events["TriggeredExitFeeRecorded"]["pubkey"] == pubkey + assert tx.events["TriggeredExitFeeRecorded"]["exitType"] == exit_type + assert tx.events["TriggeredExitFeeRecorded"]["withdrawalRequestPaidFee"] == eject_payment_value + assert tx.events["TriggeredExitFeeRecorded"]["withdrawalRequestRecordedFee"] == eject_payment_value + + +def test_easy_track_csm_settle_el_stealing_penalty(csm, accounting, node_operator, stranger): + manager_address = csm.getNodeOperator(node_operator)["managerAddress"] + set_balance_in_wei(manager_address, ETH(2)) + accounting.depositETH(node_operator, {"from": manager_address, "value": ETH(1)}) + + csm.reportELRewardsStealingPenalty(node_operator, b'\x00' * 32, ETH(0.5), {"from": CSM_COMMITTEE_MS}) + + motions_before = contracts.easy_track.getMotions() + + calldata = _encode_calldata(["uint256[]"], [[node_operator]]) + tx = contracts.easy_track.createMotion(EASYTRACK_CSM_SETTLE_EL_REWARDS_STEALING_PENALTY_FACTORY, calldata, {"from": CSM_COMMITTEE_MS}) + + motions = contracts.easy_track.getMotions() + assert len(motions) == len(motions_before) + 1 + + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + + bond_before = accounting.getBond(node_operator) + + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": stranger}, + ) + + bond_after = accounting.getBond(node_operator) + + assert bond_before > bond_after, "Bond should be decreased after settling penalty" + + +def test_easy_track_csm_set_vetted_gate_tree( + csm, accounting, node_operator, stranger +): + motions_before = contracts.easy_track.getMotions() + + new_tree_root = bytes.fromhex("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef") + new_tree_cid = "QmTest123456789" + calldata = _encode_calldata(["bytes32", "string"], [new_tree_root, new_tree_cid]) + + tx = contracts.easy_track.createMotion(EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY, calldata, {"from": CSM_COMMITTEE_MS}) + + motions = contracts.easy_track.getMotions() + assert len(motions) == len(motions_before) + 1 + + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": stranger}, + ) + + vetted_gate_tree_root_after = contracts.cs_vetted_gate.treeRoot() + vetted_gate_tree_cid_after = contracts.cs_vetted_gate.treeCid() + + assert vetted_gate_tree_root_after == ("0x" + new_tree_root.hex()), "Tree root not updated" + assert vetted_gate_tree_cid_after == new_tree_cid, "Tree CID not updated" diff --git a/tests/regression/test_easy_track.py b/tests/regression/test_easy_track.py index 78afe35f3..40d4a239b 100644 --- a/tests/regression/test_easy_track.py +++ b/tests/regression/test_easy_track.py @@ -22,9 +22,9 @@ ) from utils.test.easy_track_helpers import _encode_calldata, create_and_enact_motion - MANAGE_SIGNING_KEYS = "0x75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee" + def test_increase_nop_staking_limit( stranger, ): @@ -35,8 +35,10 @@ def test_increase_nop_staking_limit( new_staking_limit = node_operator["totalVettedValidators"] + 1 if node_operator["totalAddedValidators"] < new_staking_limit: - if not contracts.acl.hasPermission(contracts.agent, contracts.node_operators_registry, web3.keccak(text="MANAGE_SIGNING_KEYS")): - contracts.acl.grantPermission(contracts.agent, contracts.node_operators_registry, web3.keccak(text="MANAGE_SIGNING_KEYS"), {"from": contracts.agent}) + if not contracts.acl.hasPermission(contracts.agent, contracts.node_operators_registry, + web3.keccak(text="MANAGE_SIGNING_KEYS")): + contracts.acl.grantPermission(contracts.agent, contracts.node_operators_registry, + web3.keccak(text="MANAGE_SIGNING_KEYS"), {"from": contracts.agent}) contracts.node_operators_registry.addSigningKeys( no_id, 1, @@ -45,7 +47,7 @@ def test_increase_nop_staking_limit( {"from": contracts.agent}, ) - calldata = _encode_calldata(("uint256","uint256"), [no_id, new_staking_limit]) + calldata = _encode_calldata(("uint256", "uint256"), [no_id, new_staking_limit]) create_and_enact_motion(contracts.easy_track, trusted_caller, factory, calldata, stranger) diff --git a/tests/regression/test_easy_track_factories.py b/tests/regression/test_easy_track_factories.py index 2098984a9..724901e18 100644 --- a/tests/regression/test_easy_track_factories.py +++ b/tests/regression/test_easy_track_factories.py @@ -1,7 +1,12 @@ import random +from dataclasses import dataclass +from typing import List, Dict -from brownie import interface +import eth_abi +from brownie import interface, accounts, Wei from brownie.exceptions import VirtualMachineError +from eth_typing import HexStr +from eth_abi.abi import encode from configs.config_mainnet import * from utils.config import contracts, EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER @@ -14,7 +19,6 @@ simple_dvt_add_node_operators, ) - NODE_OPERATORS = [ { "address": get_operator_address(i, 2), @@ -113,6 +117,163 @@ def change_node_operator_managers(operators, stranger): create_and_enact_motion(contracts.easy_track, EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, factory, calldata, stranger) +@dataclass +class ExitRequestInput: + """Exit request input structure""" + moduleId: int + nodeOpId: int + valIndex: int + valPubkey: HexStr + valPubKeyIndex: int + + +@dataclass +class ValidatorInfo: + """Validator information from Consensus Layer""" + index: int + pubkey: HexStr + status: str + + +def encode_exit_requests_easy_track(exit_requests: List[ExitRequestInput]) -> bytes: + struct_tuples = [] + + for req in exit_requests: + # Convert public key to bytes + if req.valPubkey.startswith('0x'): + pubkey_hex = req.valPubkey[2:] + else: + pubkey_hex = req.valPubkey + + pubkey_bytes = bytes.fromhex(pubkey_hex) + if len(pubkey_bytes) != 48: + raise ValueError(f'Invalid public key length: {len(pubkey_bytes)} bytes, expected 48') + + struct_tuples.append(( + req.moduleId, # uint256 + req.nodeOpId, # uint256 + req.valIndex, # uint64 + pubkey_bytes, # bytes + req.valPubKeyIndex # uint256 + )) + + return encode( + ['(uint256,uint256,uint64,bytes,uint256)[]'], + [struct_tuples] + ) + + +def encode_exit_requests_oracle(exit_requests: List[ExitRequestInput]) -> bytes: + # Constants matching the original ejector format + MODULE_ID_LENGTH = 3 # 3 bytes + NODE_OPERATOR_ID_LENGTH = 5 # 5 bytes + VALIDATOR_INDEX_LENGTH = 8 # 8 bytes + VALIDATOR_PUB_KEY_LENGTH = 48 # 48 bytes + + # Encode the inner data (matching original ejector format) + inner_data = b'' + + for request in exit_requests: + # Module ID (3 bytes) - matching original format + inner_data += request.moduleId.to_bytes(MODULE_ID_LENGTH, byteorder='big') + + # Node Operator ID (5 bytes) - matching original format + inner_data += request.nodeOpId.to_bytes(NODE_OPERATOR_ID_LENGTH, byteorder='big') + + # Validator Index (8 bytes) + inner_data += request.valIndex.to_bytes(VALIDATOR_INDEX_LENGTH, byteorder='big') + + # Validator Public Key (48 bytes) + if request.valPubkey.startswith('0x'): + pubkey_hex = request.valPubkey[2:] + else: + pubkey_hex = request.valPubkey + + pubkey_bytes = bytes.fromhex(pubkey_hex) + if len(pubkey_bytes) != VALIDATOR_PUB_KEY_LENGTH: + raise ValueError( + f'Invalid public key length: {len(pubkey_bytes)} bytes, expected {VALIDATOR_PUB_KEY_LENGTH}') + inner_data += pubkey_bytes + + return inner_data + + +def create_exit_requests( + module_id: int, + operator_id: int, + public_keys: List[HexStr], + validators_info: Dict[HexStr, ValidatorInfo], + key_index_mapping: Dict[HexStr, int] +) -> List[ExitRequestInput]: + exit_requests = [] + + for pub_key in public_keys: + normalized_key = pub_key.lower() + + # Get key index from Keys API + key_index = key_index_mapping.get(normalized_key) + if key_index is None: + raise ValueError(f"Key index not found for public key: {pub_key}") + + # Get validator index from CL + validator_info = validators_info.get(normalized_key) + if validator_info is None: + raise ValueError(f"Validator not found in CL for public key: {pub_key}") + + exit_requests.append(ExitRequestInput( + moduleId=module_id, + nodeOpId=operator_id, + valIndex=validator_info.index, + valPubkey=pub_key, + valPubKeyIndex=key_index + )) + + return exit_requests + + +def submit_exit_hashes_curated(stranger) -> (bytes, str, str): + no_id = 1 + PUBKEYS = [ + "0xb3e9f4e915f9fb9ef9c55da1815071f3f728cc6fc434fba2c11e08db5b5fa22b71d5975cec30ef97e7fc901e5a04ee5b", + ] + keys_index_mapping = { + PUBKEYS[0]: 1, + } + exit_requests = create_exit_requests(1, no_id, PUBKEYS, { + PUBKEYS[0]: ValidatorInfo(index=12345, pubkey=PUBKEYS[0], status="active_ongoing"), + }, keys_index_mapping) + + node_operator = contracts.node_operators_registry.getNodeOperator(no_id, False) + + easy_track_exit_data = encode_exit_requests_easy_track(exit_requests) + calldata = "0x" + easy_track_exit_data.hex() + + factory = interface.CuratedSubmitExitRequestHashes(EASYTRACK_CURATED_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY) + create_and_enact_motion(contracts.easy_track, node_operator["rewardAddress"], factory, calldata, stranger) + + return encode_exit_requests_oracle(exit_requests), node_operator["rewardAddress"], PUBKEYS[0] + + +def submit_exit_hashes_sdvt(stranger) -> (bytes, str, str): + no_id = 1 + PUBKEYS = [ + "0x80e7ad4457002894ddfcc41f6589c578c965f769cf971d3fefd8d8ed59a41cb98d27c9faad9886b5492a3afbb4217ea6", + ] + keys_index_mapping = { + PUBKEYS[0]: 1, + } + exit_requests = create_exit_requests(2, no_id, PUBKEYS, { + PUBKEYS[0]: ValidatorInfo(index=12345, pubkey=PUBKEYS[0], status="active_ongoing"), + }, keys_index_mapping) + + easy_track_exit_data = encode_exit_requests_easy_track(exit_requests) + calldata = "0x" + easy_track_exit_data.hex() + factory = interface.SDVTSubmitExitRequestHashes(EASYTRACK_SIMPLE_DVT_SUBMIT_VALIDATOR_EXIT_REQUEST_HASHES_FACTORY) + create_and_enact_motion(contracts.easy_track, EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, factory, calldata, stranger) + + return encode_exit_requests_oracle(exit_requests), EASYTRACK_SIMPLE_DVT_TRUSTED_CALLER, PUBKEYS[0] + + def test_add_node_operators(stranger): fill_simple_dvt_ops_keys(stranger, 3, 5) # AddNodeOperators @@ -120,7 +281,7 @@ def test_add_node_operators(stranger): add_node_operators(NODE_OPERATORS, stranger) - no_ids = list(contracts.simple_dvt.getNodeOperatorIds(1, 100))[node_operators_count - 1 :] + no_ids = list(contracts.simple_dvt.getNodeOperatorIds(1, 100))[node_operators_count - 1:] for no_id, no in zip(no_ids, NODE_OPERATORS): no_in_contract = contracts.simple_dvt.getNodeOperator(no_id, True) @@ -393,3 +554,34 @@ def test_transfer_node_operator_manager(stranger): ) except VirtualMachineError as error: assert "OLD_MANAGER_HAS_NO_ROLE" in error.message + + +def test_curated_exit_hashes( + stranger, +): + value = contracts.withdrawal_vault.getWithdrawalRequestFee() + oracle_exit_data, caller, pubkey = submit_exit_hashes_curated(stranger) + contracts.validators_exit_bus_oracle.submitExitRequestsData((oracle_exit_data, 1), {"from": caller}) + tx = contracts.validators_exit_bus_oracle.triggerExits((oracle_exit_data, 1), [0], caller, {"from": caller, 'value': value}) + # pubkey is 48 bytes, amount is uint64 (8 bytes, big-endian) in encodePacked + assert len(tx.events["WithdrawalRequestAdded"]['request']) == 56 # 48 + 8 + pubkey_bytes = tx.events["WithdrawalRequestAdded"]['request'][:48] + _ = int.from_bytes(tx.events["WithdrawalRequestAdded"]['request'][48:], byteorder="big", signed=False) + + pubkey_hex = "0x" + pubkey_bytes.hex() + assert pubkey == pubkey_hex + +def test_sdvt_exit_hashes( + stranger, +): + value = contracts.withdrawal_vault.getWithdrawalRequestFee() + oracle_exit_data, caller, pubkey = submit_exit_hashes_sdvt(stranger) + contracts.validators_exit_bus_oracle.submitExitRequestsData((oracle_exit_data, 1), {"from": caller}) + tx = contracts.validators_exit_bus_oracle.triggerExits((oracle_exit_data, 1), [0], caller, {"from": caller, 'value': value}) + # pubkey is 48 bytes, amount is uint64 (8 bytes, big-endian) in encodePacked + assert len(tx.events["WithdrawalRequestAdded"]['request']) == 56 # 48 + 8 + pubkey_bytes = tx.events["WithdrawalRequestAdded"]['request'][:48] + _ = int.from_bytes(tx.events["WithdrawalRequestAdded"]['request'][48:], byteorder="big", signed=False) + + pubkey_hex = "0x" + pubkey_bytes.hex() + assert pubkey == pubkey_hex diff --git a/tests/regression/test_gate_seal.py b/tests/regression/test_gate_seal.py index dc1485504..f11a3c486 100644 --- a/tests/regression/test_gate_seal.py +++ b/tests/regression/test_gate_seal.py @@ -1,13 +1,19 @@ import pytest -from brownie import reverts, accounts, chain # type: ignore -from utils.test.oracle_report_helpers import oracle_report, ZERO_BYTES32 +from brownie import reverts, accounts, chain, web3, Wei # type: ignore +from eth_hash.auto import keccak + +from utils.test.exit_bus_data import LidoValidator +from utils.test.oracle_report_helpers import oracle_report, ZERO_BYTES32, wait_to_next_available_report_time, \ + prepare_exit_bus_report, reach_consensus from brownie.network.account import Account +from eth_abi.abi import encode from utils.evm_script import encode_error from utils.test.helpers import almostEqEth, ETH from utils.test.deposits_helpers import fill_deposit_buffer from utils.config import ( + TRIGGERABLE_WITHDRAWALS_GATEWAY, GATE_SEAL_COMMITTEE, contracts, WITHDRAWAL_QUEUE, @@ -33,10 +39,20 @@ def test_gate_seal_expiration(gate_seal_committee): chain.mine(1) assert contracts.gate_seal.is_expired() with reverts("gate seal: expired"): - contracts.gate_seal.seal([WITHDRAWAL_QUEUE, VALIDATORS_EXIT_BUS_ORACLE], {"from": gate_seal_committee}) + contracts.gate_seal.seal([WITHDRAWAL_QUEUE], {"from": gate_seal_committee}) + + +def test_gate_seal_twg_veb_expiration(gate_seal_committee): + assert not contracts.veb_twg_gate_seal.is_expired() + time = chain.time() + chain.sleep(GATE_SEAL_EXPIRY_TIMESTAMP - time + 1) + chain.mine(1) + assert contracts.veb_twg_gate_seal.is_expired() + with reverts("gate seal: expired"): + contracts.gate_seal.seal([TRIGGERABLE_WITHDRAWALS_GATEWAY, VALIDATORS_EXIT_BUS_ORACLE], {"from": gate_seal_committee}) -def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): +def test_gate_seal_wq_scenario(steth_holder, gate_seal_committee, eth_whale): account = accounts.at(steth_holder, force=True) REQUESTS_COUNT = 2 REQUEST_AMOUNT = ETH(1) @@ -46,7 +62,6 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): unfinalized_steth = contracts.withdrawal_queue.unfinalizedStETH() while unfinalized_steth > 0: - fill_deposit_buffer(unfinalized_steth // ETH(32) + 1) oracle_report(silent=True) @@ -84,10 +99,10 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): pending_request_ids = [event["requestId"] for event in request_tx.events["WithdrawalRequested"]] """ sealing """ - sealables = [WITHDRAWAL_QUEUE, VALIDATORS_EXIT_BUS_ORACLE] + sealables = [WITHDRAWAL_QUEUE] seal_tx = contracts.gate_seal.seal(sealables, {"from": gate_seal_committee}) - assert seal_tx.events.count("Sealed") == 2 + assert seal_tx.events.count("Sealed") == 1 for i, seal_event in enumerate(seal_tx.events["Sealed"]): assert seal_event["gate_seal"] == GATE_SEAL assert seal_event["sealed_for"] == GATE_SEAL_PAUSE_DURATION @@ -107,11 +122,6 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): assert contracts.withdrawal_queue.isPaused() assert contracts.withdrawal_queue.getResumeSinceTimestamp() == seal_tx.timestamp + GATE_SEAL_PAUSE_DURATION - assert contracts.validators_exit_bus_oracle.isPaused() - assert ( - contracts.validators_exit_bus_oracle.getResumeSinceTimestamp() == seal_tx.timestamp + GATE_SEAL_PAUSE_DURATION - ) - # reverts on requestWithdrawals contracts.lido.approve(contracts.withdrawal_queue.address, REQUESTS_SUM, {"from": steth_holder}) with reverts(encode_error("ResumedExpected()")): @@ -119,18 +129,12 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): [REQUEST_AMOUNT for _ in range(REQUESTS_COUNT)], steth_holder, {"from": steth_holder} ) - # reverts on VEBO report - with reverts(encode_error("ResumedExpected()")): - contracts.validators_exit_bus_oracle.submitReportData((1, 1, 1, 1, ZERO_BYTES32), 1, {"from": steth_holder}) - # reverts on finalization attempt with reverts(encode_error("ResumedExpected()")): contracts.withdrawal_queue.finalize(1, 1, {"from": steth_holder}) """ claim """ assert contracts.withdrawal_queue.isPaused() - assert contracts.validators_exit_bus_oracle.isPaused() - lastCheckpointIndex = contracts.withdrawal_queue.getLastCheckpointIndex() hints = contracts.withdrawal_queue.findCheckpointHints(claimable_request_ids, 1, lastCheckpointIndex) claim_balance_before = account.balance() @@ -138,7 +142,6 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): claim_balance_after = account.balance() assert contracts.withdrawal_queue.isPaused() - assert contracts.validators_exit_bus_oracle.isPaused() assert almostEqEth( claim_balance_after - claim_balance_before + claim_tx.gas_used * claim_tx.gas_price, REQUESTS_SUM @@ -161,7 +164,6 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): assert reports_passed <= MAX_REPORTS_UNTIL_RESUME assert not contracts.withdrawal_queue.isPaused() - assert not contracts.validators_exit_bus_oracle.isPaused() """ post seal claim """ lastCheckpointIndex = contracts.withdrawal_queue.getLastCheckpointIndex() @@ -174,3 +176,145 @@ def test_gate_seal_scenario(steth_holder, gate_seal_committee, eth_whale): claim_balance_after - claim_balance_before + claim_tx.gas_used * claim_tx.gas_price, REQUESTS_SUM ) assert claim_tx.events.count("WithdrawalClaimed") == REQUESTS_COUNT + + +def test_gate_seal_twg_veb_scenario(steth_holder, gate_seal_committee, eth_whale): + account = accounts.at(steth_holder, force=True) + REQUESTS_COUNT = 2 + REQUEST_AMOUNT = ETH(1) + REQUESTS_SUM = REQUESTS_COUNT * REQUEST_AMOUNT + + """ finalize all requests """ + unfinalized_steth = contracts.withdrawal_queue.unfinalizedStETH() + + while unfinalized_steth > 0: + fill_deposit_buffer(unfinalized_steth // ETH(32) + 1) + + oracle_report(silent=True) + unfinalized_steth = contracts.withdrawal_queue.unfinalizedStETH() + + """ requests to be finalized """ + contracts.lido.approve(contracts.withdrawal_queue.address, REQUESTS_SUM, {"from": steth_holder}) + request_tx = contracts.withdrawal_queue.requestWithdrawals( + [REQUEST_AMOUNT for _ in range(REQUESTS_COUNT)], steth_holder, {"from": steth_holder} + ) + claimable_request_ids = [event["requestId"] for event in request_tx.events["WithdrawalRequested"]] + + """ finalization """ + report_tx = oracle_report(silent=True)[0] + + # on second report requests will get finalized for sure + if not report_tx.events.count("WithdrawalsFinalized") == 1: + report_tx = oracle_report(silent=True)[0] + + while report_tx.events["WithdrawalsFinalized"][0]["to"] != claimable_request_ids[-1]: + report_tx = oracle_report(silent=True)[0] + assert report_tx.events.count("WithdrawalsFinalized") == 1 + + post_report_statuses = contracts.withdrawal_queue.getWithdrawalStatus(claimable_request_ids, {"from": steth_holder}) + for i, _ in enumerate(claimable_request_ids): + (_, _, _, _, isFinalized, isClaimed) = post_report_statuses[i] + assert isFinalized + assert not isClaimed + + """ requests to be left pending """ + contracts.lido.approve(contracts.withdrawal_queue.address, REQUESTS_SUM, {"from": steth_holder}) + request_tx = contracts.withdrawal_queue.requestWithdrawals( + [REQUEST_AMOUNT for _ in range(REQUESTS_COUNT)], steth_holder, {"from": steth_holder} + ) + pending_request_ids = [event["requestId"] for event in request_tx.events["WithdrawalRequested"]] + + """ sealing """ + sealables = [TRIGGERABLE_WITHDRAWALS_GATEWAY, VALIDATORS_EXIT_BUS_ORACLE] + seal_tx = contracts.veb_twg_gate_seal.seal(sealables, {"from": gate_seal_committee}) + + assert seal_tx.events.count("Sealed") == 2 + for i, seal_event in enumerate(seal_tx.events["Sealed"]): + assert seal_event["gate_seal"] == contracts.veb_twg_gate_seal.address + assert seal_event["sealed_for"] == GATE_SEAL_PAUSE_DURATION + assert seal_event["sealed_by"] == gate_seal_committee + assert seal_event["sealable"] == sealables[i] + assert seal_event["sealed_at"] == seal_tx.timestamp + + # brownie for some reason fails to decode second event + # assert seal_tx.events.count("Paused") == 2 + for pause_event in seal_tx.events["Paused"]: + assert pause_event["duration"] == GATE_SEAL_PAUSE_DURATION + + assert contracts.veb_twg_gate_seal.is_expired() + with reverts("gate seal: expired"): + seal_tx = contracts.veb_twg_gate_seal.seal(sealables, {"from": gate_seal_committee}) + + assert contracts.triggerable_withdrawals_gateway.isPaused() + assert contracts.triggerable_withdrawals_gateway.getResumeSinceTimestamp() == seal_tx.timestamp + GATE_SEAL_PAUSE_DURATION + + assert contracts.validators_exit_bus_oracle.isPaused() + assert ( + contracts.validators_exit_bus_oracle.getResumeSinceTimestamp() == seal_tx.timestamp + GATE_SEAL_PAUSE_DURATION + ) + + value = Wei('1 ether') + # reverts on VEBO report + with reverts(encode_error("ResumedExpected()")): + contracts.validators_exit_bus_oracle.submitReportData((1, 1, 1, 1, ZERO_BYTES32), 1, {"from": steth_holder}) + + # reverts on VEBO triggerExits + with reverts(encode_error("ResumedExpected()")): + contracts.validators_exit_bus_oracle.triggerExits(("0x0000000000000000000000000000000000000000000", 1), [1, 2, 3], steth_holder, {"from": steth_holder, 'value': value}) + + """ claim """ + assert contracts.triggerable_withdrawals_gateway.isPaused() + assert contracts.validators_exit_bus_oracle.isPaused() + + """ accounting oracle reports until we pass pause and claim""" + MAX_REPORTS_UNTIL_RESUME = ( + GATE_SEAL_PAUSE_DURATION // (CHAIN_SECONDS_PER_SLOT * CHAIN_SLOTS_PER_EPOCH * AO_EPOCHS_PER_FRAME) + 2 + ) + reports_passed = 0 + for i in range(MAX_REPORTS_UNTIL_RESUME): + (report_tx, _) = oracle_report(silent=False) + print( + f"Oracle report {reports_passed} at {report_tx.timestamp}/{seal_tx.timestamp + GATE_SEAL_PAUSE_DURATION} seconds to resume" + ) + + assert not contracts.triggerable_withdrawals_gateway.isPaused() + assert not contracts.validators_exit_bus_oracle.isPaused() + + """ post seal """ + unreachable_cl_validator_index = 100_000_000 + no_global_index = (module_id, no_id) = (1, 33) + validator_key = contracts.node_operators_registry.getSigningKey(no_id, 1)[0] + + validator = LidoValidator(index=unreachable_cl_validator_index, pubkey=validator_key) + + ref_slot = _wait_for_next_ref_slot() + report, report_hash = prepare_exit_bus_report([(no_global_index, validator)], ref_slot) + consensus_version = contracts.validators_exit_bus_oracle.getConsensusVersion() + + submitter = reach_consensus( + ref_slot, report_hash, consensus_version, contracts.hash_consensus_for_validators_exit_bus_oracle + ) + hash = web3.keccak(encode(['bytes', 'uint256'], [report[4], 1])) + (_,_,_, vebInitLimit1, vebInitLimit2) = contracts.validators_exit_bus_oracle.getExitRequestLimitFullInfo() + contracts.validators_exit_bus_oracle.submitExitRequestsHash(hash, {"from": "0xFE5986E06210aC1eCC1aDCafc0cc7f8D63B3F977"}) + contracts.validators_exit_bus_oracle.submitExitRequestsData((report[4], 1), {"from": submitter}) + (_,_,_, twgInitLimit1, twgInitLimit2) = contracts.triggerable_withdrawals_gateway.getExitRequestLimitFullInfo() + tx = contracts.validators_exit_bus_oracle.triggerExits((report[4], 1), [0], steth_holder, {"from": steth_holder, 'value': value}) + + (_,_,_, twgLimit1, twgLimit2) = contracts.triggerable_withdrawals_gateway.getExitRequestLimitFullInfo() + (_,_,_, vebLimit1, vebLimit2) = contracts.validators_exit_bus_oracle.getExitRequestLimitFullInfo() + assert vebLimit1 < vebInitLimit1 + assert vebLimit2 < vebInitLimit2 + assert twgLimit1 < twgInitLimit1 + assert twgLimit2 < twgInitLimit2 + assert len(tx.events["WithdrawalRequestAdded"]['request']) == 56 # 48 + 8 + pubkey_bytes = tx.events["WithdrawalRequestAdded"]['request'][:48] + _ = int.from_bytes(tx.events["WithdrawalRequestAdded"]['request'][48:], byteorder="big", signed=False) + + pubkey_hex = "0x" + pubkey_bytes.hex() + assert validator_key == pubkey_hex + +def _wait_for_next_ref_slot(): + wait_to_next_available_report_time(contracts.hash_consensus_for_validators_exit_bus_oracle) + ref_slot, _ = contracts.hash_consensus_for_validators_exit_bus_oracle.getCurrentFrame() + return ref_slot diff --git a/tests/regression/test_permissions.py b/tests/regression/test_permissions.py index b36977bd2..b3d5445ed 100644 --- a/tests/regression/test_permissions.py +++ b/tests/regression/test_permissions.py @@ -39,6 +39,7 @@ HASH_CONSENSUS_FOR_VEBO, HASH_CONSENSUS_FOR_AO, VALIDATORS_EXIT_BUS_ORACLE, + VEB_TWG_GATE_SEAL, ACCOUNTING_ORACLE, WITHDRAWAL_QUEUE, BURNER, @@ -47,11 +48,16 @@ SIMPLE_DVT, CSM_ADDRESS, CS_ACCOUNTING_ADDRESS, - CS_GATE_SEAL_ADDRESS, - CS_VERIFIER_ADDRESS, + CS_GATE_SEAL_V2_ADDRESS, + CS_VERIFIER_V2_ADDRESS, CS_FEE_DISTRIBUTOR_ADDRESS, CS_FEE_ORACLE_ADDRESS, CS_ORACLE_HASH_CONSENSUS_ADDRESS, + CS_PERMISSIONLESS_GATE_ADDRESS, + CS_VETTED_GATE_ADDRESS, + CS_PARAMS_REGISTRY_ADDRESS, + CS_STRIKES_ADDRESS, + CS_EJECTOR_ADDRESS, L1_EMERGENCY_BRAKES_MULTISIG, DUAL_GOVERNANCE_EXECUTORS, RESEAL_MANAGER, @@ -92,6 +98,8 @@ def protocol_permissions(): "REPORT_EXITED_VALIDATORS_ROLE": [contracts.accounting_oracle], "UNSAFE_SET_EXITED_VALIDATORS_ROLE": [], "REPORT_REWARDS_MINTED_ROLE": [contracts.lido], + "REPORT_VALIDATOR_EXITING_STATUS_ROLE": [contracts.validator_exit_verifier], + "REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE": [contracts.triggerable_withdrawals_gateway], }, }, WITHDRAWAL_QUEUE: { @@ -128,10 +136,12 @@ def protocol_permissions(): "roles": { "DEFAULT_ADMIN_ROLE": [contracts.agent], "SUBMIT_DATA_ROLE": [], - "PAUSE_ROLE": [GATE_SEAL, RESEAL_MANAGER], + "PAUSE_ROLE": [VEB_TWG_GATE_SEAL, RESEAL_MANAGER], "RESUME_ROLE": [RESEAL_MANAGER], "MANAGE_CONSENSUS_CONTRACT_ROLE": [], "MANAGE_CONSENSUS_VERSION_ROLE": [], + "EXIT_REQUEST_LIMIT_MANAGER_ROLE": [], + "SUBMIT_REPORT_HASH_ROLE": [EASYTRACK_EVMSCRIPT_EXECUTOR], }, }, HASH_CONSENSUS_FOR_AO: { @@ -322,12 +332,12 @@ def protocol_permissions(): "roles": { "DEFAULT_ADMIN_ROLE": [contracts.agent], "STAKING_ROUTER_ROLE": [STAKING_ROUTER], - "PAUSE_ROLE": [CS_GATE_SEAL_ADDRESS, RESEAL_MANAGER], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], "REPORT_EL_REWARDS_STEALING_PENALTY_ROLE": [CSM_COMMITTEE_MS], "SETTLE_EL_REWARDS_STEALING_PENALTY_ROLE": [EASYTRACK_EVMSCRIPT_EXECUTOR], - "VERIFIER_ROLE": [CS_VERIFIER_ADDRESS], + "CREATE_NODE_OPERATOR_ROLE": [CS_PERMISSIONLESS_GATE_ADDRESS, CS_VETTED_GATE_ADDRESS], + "VERIFIER_ROLE": [CS_VERIFIER_V2_ADDRESS], "RESUME_ROLE": [RESEAL_MANAGER], - "MODULE_MANAGER_ROLE": [], "RECOVERER_ROLE": [], }, }, @@ -338,11 +348,9 @@ def protocol_permissions(): "proxy_owner": contracts.agent, "roles": { "DEFAULT_ADMIN_ROLE": [contracts.agent], - "SET_BOND_CURVE_ROLE": [CSM_ADDRESS, CSM_COMMITTEE_MS], - "RESET_BOND_CURVE_ROLE": [CSM_ADDRESS, CSM_COMMITTEE_MS], - "PAUSE_ROLE": [CS_GATE_SEAL_ADDRESS, RESEAL_MANAGER], + "SET_BOND_CURVE_ROLE": [CS_VETTED_GATE_ADDRESS, CSM_COMMITTEE_MS], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], "RESUME_ROLE": [RESEAL_MANAGER], - "ACCOUNTING_MANAGER_ROLE": [], "MANAGE_BOND_CURVES_ROLE": [], "RECOVERER_ROLE": [], }, @@ -366,8 +374,7 @@ def protocol_permissions(): "DEFAULT_ADMIN_ROLE": [contracts.agent], "MANAGE_CONSENSUS_CONTRACT_ROLE": [], "MANAGE_CONSENSUS_VERSION_ROLE": [], - "PAUSE_ROLE": [CS_GATE_SEAL_ADDRESS, RESEAL_MANAGER], - "CONTRACT_MANAGER_ROLE": [], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], "SUBMIT_DATA_ROLE": [], "RESUME_ROLE": [RESEAL_MANAGER], "RECOVERER_ROLE": [], @@ -386,6 +393,69 @@ def protocol_permissions(): "MANAGE_REPORT_PROCESSOR_ROLE": [], }, }, + CS_VERIFIER_V2_ADDRESS: { + "contract_name": "CSVerifier", + "contract": contracts.cs_verifier, + "type": "CustomApp", + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], + "RESUME_ROLE": [RESEAL_MANAGER], + } + }, + CS_PARAMS_REGISTRY_ADDRESS: { + "contract_name": "CSParametersRegistry", + "contract": contracts.cs_parameters_registry, + "type": "CustomApp", + "proxy_owner": contracts.agent, + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + }, + }, + CS_STRIKES_ADDRESS: { + "contract_name": "CSStrikes", + "contract": contracts.cs_strikes, + "type": "CustomApp", + "proxy_owner": contracts.agent, + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + }, + }, + CS_EJECTOR_ADDRESS: { + "contract_name": "CSEjector", + "contract": contracts.cs_ejector, + "type": "CustomApp", + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], + "RESUME_ROLE": [RESEAL_MANAGER], + "RECOVERER_ROLE": [], + } + }, + CS_VETTED_GATE_ADDRESS: { + "contract_name": "VettedGate", + "contract": contracts.cs_vetted_gate, + "type": "CustomApp", + "proxy_owner": contracts.agent, + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + "PAUSE_ROLE": [CS_GATE_SEAL_V2_ADDRESS, RESEAL_MANAGER], + "RESUME_ROLE": [RESEAL_MANAGER], + "RECOVERER_ROLE": [], + "SET_TREE_ROLE": [EASYTRACK_EVMSCRIPT_EXECUTOR], + "START_REFERRAL_SEASON_ROLE": [contracts.agent], + "END_REFERRAL_SEASON_ROLE": [CSM_COMMITTEE_MS], + } + }, + CS_PERMISSIONLESS_GATE_ADDRESS: { + "contract_name": "PermissionlessGate", + "contract": contracts.cs_permissionless_gate, + "type": "CustomApp", + "roles": { + "DEFAULT_ADMIN_ROLE": [contracts.agent], + "RECOVERER_ROLE": [], + } + }, INSURANCE_FUND: { "contract_name": "InsuranceFund", "contract": contracts.insurance_fund, @@ -538,11 +608,13 @@ def get_http_w3_provider_url(): assert False, 'Web3 HTTP Provider token env var not found' + def get_max_log_range(): if os.getenv("MAX_GET_LOGS_RANGE") is not None: return int(os.getenv("MAX_GET_LOGS_RANGE")) return 100000 + def active_aragon_roles(protocol_permissions): local_rpc_provider = web3 remote_rpc_provider = Web3(Web3.HTTPProvider(get_http_w3_provider_url())) diff --git a/tests/regression/test_sanity_checks.py b/tests/regression/test_sanity_checks.py index 053cd517a..3314d6c6a 100644 --- a/tests/regression/test_sanity_checks.py +++ b/tests/regression/test_sanity_checks.py @@ -218,7 +218,7 @@ def test_accounting_oracle_too_much_extra_data(extra_data_service): operators[(nor_module_id, i)] = total_exited_validators_count + 1 i = i + 1 - extra_data = extra_data_service.collect({}, operators, item_count, 1) + extra_data = extra_data_service.collect(operators, item_count, 1) with reverts( encode_error( diff --git a/tests/regression/test_sdvt_rewards_happy_path.py b/tests/regression/test_sdvt_rewards_happy_path.py index f4696a459..12d47ee01 100644 --- a/tests/regression/test_sdvt_rewards_happy_path.py +++ b/tests/regression/test_sdvt_rewards_happy_path.py @@ -108,8 +108,7 @@ def test_rewards_distribution_happy_path(simple_dvt_module_id, cluster_participa # fill the deposit buffer deposits_count = 10 - fill_deposit_buffer(deposits_count) - + fill_deposit_buffer(deposits_count, heuristic=10000) # deposit to simple dvt module_summary_before = staking_router.getStakingModuleSummary(simple_dvt_module_id) lido.deposit(deposits_count, simple_dvt_module_id, "0x", {"from": deposit_security_module}) diff --git a/tests/regression/test_staking_module_happy_path.py b/tests/regression/test_staking_module_happy_path.py index 497b25e85..375bf74a9 100644 --- a/tests/regression/test_staking_module_happy_path.py +++ b/tests/regression/test_staking_module_happy_path.py @@ -1,17 +1,17 @@ import pytest from web3 import Web3 import eth_abi -from brownie import chain, ZERO_ADDRESS, web3 +from brownie import web3 from utils.staking_module import calc_module_reward_shares from utils.test.extra_data import ( ExtraDataService, ) -from utils.test.helpers import shares_balance, ETH, almostEqWithDiff +from utils.test.helpers import shares_balance, ETH from utils.test.oracle_report_helpers import ( oracle_report, ) -from utils.config import contracts, STAKING_ROUTER, EASYTRACK_EVMSCRIPT_EXECUTOR +from utils.config import contracts, STAKING_ROUTER from utils.test.node_operators_helpers import distribute_reward, node_operator_gindex from utils.test.simple_dvt_helpers import fill_simple_dvt_ops_keys from utils.test.staking_router_helpers import set_staking_module_status, StakingModuleStatus @@ -107,22 +107,9 @@ def parse_exited_signing_keys_count_changed_logs(logs): return res -def parse_stuck_penalty_state_changed_logs(logs): - res = [] - for l in logs: - data = eth_abi.decode(["uint256", "uint256", "uint256"], l["data"]) - res.append( - { - "nodeOperatorId": eth_abi.decode(["uint256"], l["topics"][1])[0], - "stuckValidatorsCount": data[0], - "refundedValidatorsCount": data[1], - "stuckPenaltyEndTimestamp": data[2], - } - ) - return res -def module_happy_path(staking_module, extra_data_service, impersonated_agent, eth_whale, stranger, helpers): +def module_happy_path(staking_module, extra_data_service, impersonated_agent, stranger, helpers): nor_exited_count, _, _ = contracts.staking_router.getStakingModuleSummary(staking_module.module_id) # all_modules = contracts.staking_router.getStakingModules() @@ -169,17 +156,12 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 30, impersonated_agent) - penalty_delay = staking_module.getStuckPenaltyDelay() - - no1_summary = staking_module.getNodeOperatorSummary(no1_id) no1_reward_address = staking_module.getNodeOperator(no1_id, False)["rewardAddress"] no1_balance_shares_before = shares_balance(no1_reward_address) - no2_summary = staking_module.getNodeOperatorSummary(no2_id) no2_reward_address = staking_module.getNodeOperator(no2_id, False)["rewardAddress"] no2_balance_shares_before = shares_balance(no2_reward_address) - no3_summary = staking_module.getNodeOperatorSummary(no3_id) no3_reward_address = staking_module.getNodeOperator(no3_id, False)["rewardAddress"] no3_balance_shares_before = shares_balance(no3_reward_address) @@ -208,26 +190,20 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_first_report assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_first_report - # Case 1 - # --- operator "1st" had 5 keys (exited), and 2 keys got stuck (stuck) - # --- operator "2nd" had 5 keys (exited), and 2 keys got stuck (stuck) + # Test Case: Basic Exit Handling + # --- operator "1st" had 5 keys (exited) + # --- operator "2nd" had 5 keys (exited) # - Send report - # - Check rewards shares for "3d" NO and tested NO (should be half of expected) - # - Check deposits (should be 0 for penalized NOs) - # - Check burned shares + # - Check rewards shares distribution # - Check NOs stats # - Check Report events # Prepare extra data - vals_stuck_non_zero = { - node_operator_gindex(staking_module.module_id, no1_id): 2, - node_operator_gindex(staking_module.module_id, no2_id): 2, - } vals_exited_non_zero = { node_operator_gindex(staking_module.module_id, no1_id): 5, node_operator_gindex(staking_module.module_id, no2_id): 5, } - extra_data = extra_data_service.collect(vals_stuck_non_zero, vals_exited_non_zero, 10, 10) + extra_data = extra_data_service.collect(vals_exited_non_zero, 10, 10) # shares before report no1_balance_shares_before = shares_balance(no1_reward_address) @@ -237,17 +213,17 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 30, impersonated_agent) module_shares_dust = shares_balance(staking_module) - # Second report - first NO and second NO has stuck/exited + # Second report - first NO and second NO has exited (report_tx, extra_report_tx_list) = oracle_report( exclude_vaults_balances=True, extraDataFormat=1, extraDataHashList=extra_data.extra_data_hash_list, - extraDataItemsCount=2, + extraDataItemsCount=extra_data.items_count, extraDataList=extra_data.extra_data_list, numExitedValidatorsByStakingModule=[nor_exited_count + 10], stakingModuleIdsWithNewlyExitedValidators=[staking_module.module_id], ) - distribute_reward_tx = distribute_reward(staking_module, stranger.address) + distribute_reward(staking_module, stranger.address) # shares after report no1_summary = staking_module.getNodeOperatorSummary(no1_id) @@ -267,38 +243,14 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et no2_balance_shares_after = shares_balance(no2_reward_address) no3_balance_shares_after = shares_balance(no3_reward_address) - # check shares by report with penalty - assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_second_report // 2 - assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_second_report // 2 + assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_second_report + assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_second_report assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_second_report - - # Check burn shares - no1_amount_penalty = no1_rewards_after_second_report // 2 - no2_amount_penalty = no2_rewards_after_second_report // 2 - penalty_shares = no1_amount_penalty + no2_amount_penalty - - assert distribute_reward_tx.events["StETHBurnRequested"]["amountOfShares"] >= penalty_shares - # NO stats - assert no1_summary["stuckValidatorsCount"] == 2 assert no1_summary["totalExitedValidators"] == 5 - assert no1_summary["refundedValidatorsCount"] == 0 - assert no1_summary["stuckPenaltyEndTimestamp"] == 0 - - assert no2_summary["stuckValidatorsCount"] == 2 assert no2_summary["totalExitedValidators"] == 5 - assert no2_summary["refundedValidatorsCount"] == 0 - assert no2_summary["stuckPenaltyEndTimestamp"] == 0 - - assert no3_summary["stuckValidatorsCount"] == 0 assert no3_summary["totalExitedValidators"] == 0 - assert no3_summary["refundedValidatorsCount"] == 0 - assert no3_summary["stuckPenaltyEndTimestamp"] == 0 - - assert staking_module.isOperatorPenalized(no1_id) - assert staking_module.isOperatorPenalized(no2_id) - assert not staking_module.isOperatorPenalized(no3_id) # Events exited_signing_keys_count_events = parse_exited_signing_keys_count_changed_logs( @@ -310,396 +262,8 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et assert exited_signing_keys_count_events[1]["nodeOperatorId"] == no2_id assert exited_signing_keys_count_events[1]["exitedValidatorsCount"][0] == 5 - stuck_penalty_state_changed_events = parse_stuck_penalty_state_changed_logs( - filter_transfer_logs( - extra_report_tx_list[0].logs, web3.keccak(text="StuckPenaltyStateChanged(uint256,uint256,uint256,uint256)") - ) - ) - assert stuck_penalty_state_changed_events[0]["nodeOperatorId"] == no1_id - assert stuck_penalty_state_changed_events[0]["stuckValidatorsCount"] == 2 - - assert stuck_penalty_state_changed_events[1]["nodeOperatorId"] == no2_id - assert stuck_penalty_state_changed_events[1]["stuckValidatorsCount"] == 2 - # Deposit keys - ( - no1_deposited_keys_before, - no2_deposited_keys_before, - no3_deposited_keys_before, - no1_deposited_keys_after, - no2_deposited_keys_after, - no3_deposited_keys_after, - ) = deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 50, impersonated_agent) - - # check don't change deposited keys for penalized NO - assert no1_deposited_keys_before == no1_deposited_keys_after - assert no2_deposited_keys_before == no2_deposited_keys_after - assert no3_deposited_keys_before != no3_deposited_keys_after - - # Case 2 - # --- "1st" NO exited the keys (stuck == 0, exited increased by the number of stacks) - # --- BUT the penalty still affects both - # - Send report - # - Check rewards shares for NO3 and tested NO (should be half of expected) - # - Check burned shares - # - Check NOs stats - # - Check Report events - - # Prepare extra data - first node operator has exited 2 + 5 keys an stuck 0 - vals_stuck_non_zero = { - node_operator_gindex(staking_module.module_id, no1_id): 0, - } - vals_exited_non_zero = { - node_operator_gindex(staking_module.module_id, no1_id): 7, - } - extra_data = extra_data_service.collect(vals_stuck_non_zero, vals_exited_non_zero, 10, 10) - - # shares before report - no1_balance_shares_before = shares_balance(no1_reward_address) - no2_balance_shares_before = shares_balance(no2_reward_address) - no3_balance_shares_before = shares_balance(no3_reward_address) - - # Third report - first NO: increase stuck to 0, desc exited to 7 = 5 + 2 - # Second NO: same as prev report - module_shares_dust = shares_balance(staking_module) - (report_tx, extra_report_tx_list) = oracle_report( - cl_diff=ETH(10), - exclude_vaults_balances=True, - extraDataFormat=1, - extraDataHashList=extra_data.extra_data_hash_list, - extraDataItemsCount=2, - extraDataList=extra_data.extra_data_list, - numExitedValidatorsByStakingModule=[nor_exited_count + 12], - stakingModuleIdsWithNewlyExitedValidators=[staking_module.module_id], - ) - distribute_reward_tx= distribute_reward(staking_module, stranger.address) - - no1_summary = staking_module.getNodeOperatorSummary(no1_id) - no2_summary = staking_module.getNodeOperatorSummary(no2_id) - no3_summary = staking_module.getNodeOperatorSummary(no3_id) - - # shares after report - no1_balance_shares_after = shares_balance(no1_reward_address) - no2_balance_shares_after = shares_balance(no2_reward_address) - no3_balance_shares_after = shares_balance(no3_reward_address) - - # expected shares - minted_share = ( - calc_module_reward_shares(staking_module.module_id, report_tx.events["TokenRebased"]["sharesMintedAsFees"]) - + module_shares_dust - ) - no1_rewards_after_third_report = calc_no_rewards(staking_module, no_id=no1_id, minted_shares=minted_share) - no2_rewards_after_third_report = calc_no_rewards(staking_module, no_id=no2_id, minted_shares=minted_share) - no3_rewards_after_third_report = calc_no_rewards(staking_module, no_id=no3_id, minted_shares=minted_share) - - # first NO has penalty has a penalty until stuckPenaltyEndTimestamp - # check shares by report with penalty - # diff by 1 share because of rounding - assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_third_report // 2 - assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_third_report // 2 - assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_third_report - - # Check burn shares - no1_amount_penalty = no1_rewards_after_third_report // 2 - no2_amount_penalty = no2_rewards_after_third_report // 2 - penalty_shares = no1_amount_penalty + no2_amount_penalty - # diff by 2 share because of rounding - # TODO: Fix below check when nor contains other penalized node operators - # assert almostEqWithDiff(extra_report_tx_list[0].events["StETHBurnRequested"]["amountOfShares"], penalty_shares, 2) - assert distribute_reward_tx.events["StETHBurnRequested"]["amountOfShares"] >= penalty_shares - - # NO stats - assert no3_summary["stuckPenaltyEndTimestamp"] == 0 - - assert no1_summary["stuckValidatorsCount"] == 0 - assert no1_summary["totalExitedValidators"] == 7 - assert no1_summary["refundedValidatorsCount"] == 0 - # first NO has penalty has a penalty until stuckPenaltyEndTimestamp - assert no1_summary["stuckPenaltyEndTimestamp"] > chain.time() - - assert no2_summary["stuckValidatorsCount"] == 2 - assert no2_summary["totalExitedValidators"] == 5 - assert no2_summary["refundedValidatorsCount"] == 0 - assert no2_summary["stuckPenaltyEndTimestamp"] == 0 - - assert staking_module.isOperatorPenalized(no1_id) == True - assert staking_module.isOperatorPenalized(no2_id) == True - assert staking_module.isOperatorPenalized(no3_id) == False - - # events - exited_signing_keys_count_events = parse_exited_signing_keys_count_changed_logs( - filter_transfer_logs(extra_report_tx_list[0].logs, web3.keccak(text="ExitedSigningKeysCountChanged(uint256,uint256)")) - ) - assert exited_signing_keys_count_events[0]["nodeOperatorId"] == no1_id - assert exited_signing_keys_count_events[0]["exitedValidatorsCount"][0] == 7 - - stuck_penalty_state_changed_events = parse_stuck_penalty_state_changed_logs( - filter_transfer_logs( - extra_report_tx_list[0].logs, web3.keccak(text="StuckPenaltyStateChanged(uint256,uint256,uint256,uint256)") - ) - ) - assert stuck_penalty_state_changed_events[0]["nodeOperatorId"] == no1_id - assert stuck_penalty_state_changed_events[0]["stuckValidatorsCount"] == 0 - - # Case 3 - # -- PENALTY_DELAY time passes - # -- A new report comes in and says "2nd" NO still has a stuck of keys - # -- "1st" NO is fine - # - Wait PENALTY_DELAY time - # - Send report - # - Check rewards shares for "3d" NO and tested NO (should be half for "2nd" NO) - # - Check deposits (should be 0 for "2nd" NO) - # - Check burned shares - # - Check NOs stats - - # sleep PENALTY_DELAY time - chain.sleep(penalty_delay + 1) - chain.mine() - - # Clear penalty for first NO after penalty delay - staking_module.clearNodeOperatorPenalty(no1_id, {"from": impersonated_agent}) - - # Prepare extra data for report by second NO - vals_stuck_non_zero = { - node_operator_gindex(staking_module.module_id, no2_id): 2, - } - vals_exited_non_zero = { - node_operator_gindex(staking_module.module_id, no2_id): 5, - } - extra_data = extra_data_service.collect(vals_stuck_non_zero, vals_exited_non_zero, 10, 10) - - # shares before report - no1_balance_shares_before = shares_balance(no1_reward_address) - no2_balance_shares_before = shares_balance(no2_reward_address) - no3_balance_shares_before = shares_balance(no3_reward_address) - - # Fourth report - second NO: has stuck 2 keys - module_shares_dust = shares_balance(staking_module) - (report_tx, extra_report_tx_list) = oracle_report( - exclude_vaults_balances=True, - extraDataFormat=1, - extraDataHashList=extra_data.extra_data_hash_list, - extraDataItemsCount=2, - extraDataList=extra_data.extra_data_list, - numExitedValidatorsByStakingModule=[nor_exited_count + 12], - stakingModuleIdsWithNewlyExitedValidators=[staking_module.module_id], - ) - distribute_reward_tx = distribute_reward(staking_module, stranger.address) - - no1_summary = staking_module.getNodeOperatorSummary(no1_id) - no2_summary = staking_module.getNodeOperatorSummary(no2_id) - no3_summary = staking_module.getNodeOperatorSummary(no3_id) - - # shares after report - no1_balance_shares_after = shares_balance(no1_reward_address) - no2_balance_shares_after = shares_balance(no2_reward_address) - no3_balance_shares_after = shares_balance(no3_reward_address) - - # expected shares - minted_share = ( - calc_module_reward_shares(staking_module.module_id, report_tx.events["TokenRebased"]["sharesMintedAsFees"]) - + module_shares_dust - ) - no1_rewards_after_fourth_report = calc_no_rewards(staking_module, no_id=no1_id, minted_shares=minted_share) - no2_rewards_after_fourth_report = calc_no_rewards(staking_module, no_id=no2_id, minted_shares=minted_share) - no3_rewards_after_fourth_report = calc_no_rewards(staking_module, no_id=no3_id, minted_shares=minted_share) - - # Penalty ended for first operator - # check shares by report with penalty for second NO - # diff by 1 share because of rounding - assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_fourth_report - assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_fourth_report // 2 - assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_fourth_report - - # Check burn shares - no2_amount_penalty = no2_rewards_after_fourth_report // 2 - # diff by 2 share because of rounding - # TODO: Fix below check when nor contains other penalized node operators - # assert almostEqWithDiff(extra_report_tx_list[0].events["StETHBurnRequested"]["amountOfShares"], amount_penalty_second_no, 1) - assert distribute_reward_tx.events["StETHBurnRequested"]["amountOfShares"] >= no2_amount_penalty - - assert no3_summary["stuckPenaltyEndTimestamp"] == 0 - - assert no1_summary["stuckValidatorsCount"] == 0 - assert no1_summary["totalExitedValidators"] == 7 - assert no1_summary["refundedValidatorsCount"] == 0 - # Penalty ended for first operator - assert no1_summary["stuckPenaltyEndTimestamp"] < chain.time() - - assert no2_summary["stuckValidatorsCount"] == 2 - assert no2_summary["totalExitedValidators"] == 5 - assert no2_summary["refundedValidatorsCount"] == 0 - assert no2_summary["stuckPenaltyEndTimestamp"] == 0 - - assert not staking_module.isOperatorPenalized(no1_id) - assert staking_module.isOperatorPenalized(no2_id) - assert not staking_module.isOperatorPenalized(no3_id) - - # Deposit - ( - no1_deposited_keys_before, - no2_deposited_keys_before, - no3_deposited_keys_before, - no1_deposited_keys_after, - no2_deposited_keys_after, - no3_deposited_keys_after, - ) = deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 50, impersonated_agent) - - # check don't change deposited keys for penalized NO (only second NO) - assert no1_deposited_keys_before != no1_deposited_keys_after - assert no2_deposited_keys_before == no2_deposited_keys_after - assert no3_deposited_keys_before != no3_deposited_keys_after - - # Case 4 - # -- Do key refend (redunded == stuck) for X2 - # -- A new report arrives and says that everything remains the same - # _ Refund 2 keys Second NO - # - Send report - # - Check rewards shares for "3d" NO and tested NO (should be half for "2nd" NO) - # - Check burned shares - # - Check NOs stats - - # # Refund 2 keys Second NO - contracts.staking_router.updateRefundedValidatorsCount( - staking_module.module_id, no2_id, 2, {"from": impersonated_agent} - ) - - # shares before report - no1_balance_shares_before = shares_balance(no1_reward_address) - no2_balance_shares_before = shares_balance(no2_reward_address) - no3_balance_shares_before = shares_balance(no3_reward_address) - - # Fifth report - module_shares_dust = shares_balance(staking_module) - (report_tx, extra_report_tx_list) = oracle_report(exclude_vaults_balances=True) - distribute_reward_tx = distribute_reward(staking_module, stranger.address) - - # shares after report - no1_balance_shares_after = shares_balance(no1_reward_address) - no2_balance_shares_after = shares_balance(no2_reward_address) - no3_balance_shares_after = shares_balance(no3_reward_address) - - no1_summary = staking_module.getNodeOperatorSummary(no1_id) - no2_summary = staking_module.getNodeOperatorSummary(no2_id) - no3_summary = staking_module.getNodeOperatorSummary(no3_id) - - # expected shares - minted_share = ( - calc_module_reward_shares(staking_module.module_id, report_tx.events["TokenRebased"]["sharesMintedAsFees"]) - + module_shares_dust - ) - no1_rewards_after_fifth_report = calc_no_rewards(staking_module, no_id=no1_id, minted_shares=minted_share) - no2_rewards_after_fifth_report = calc_no_rewards(staking_module, no_id=no2_id, minted_shares=minted_share) - no3_rewards_after_fifth_report = calc_no_rewards(staking_module, no_id=no3_id, minted_shares=minted_share) - - # Penalty only for second operator - # diff by 1 share because of rounding - assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_fifth_report - assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_fifth_report // 2 - assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_fifth_report - - # Check burn shares - no2_amount_penalty = no2_rewards_after_fifth_report // 2 - # diff by 2 share because of rounding - # TODO: Fix below check when nor contains other penalized node operators - # assert almostEqWithDiff(extra_report_tx_list[0].events["StETHBurnRequested"]["amountOfShares"], amount_penalty_second_no, 1) - assert distribute_reward_tx.events["StETHBurnRequested"]["amountOfShares"] >= no2_amount_penalty - - assert no3_summary["stuckPenaltyEndTimestamp"] == 0 - - assert no1_summary["stuckValidatorsCount"] == 0 - assert no1_summary["totalExitedValidators"] == 7 - assert no1_summary["refundedValidatorsCount"] == 0 - assert no1_summary["stuckPenaltyEndTimestamp"] < chain.time() - - assert no2_summary["stuckValidatorsCount"] == 2 - assert no2_summary["totalExitedValidators"] == 5 - assert no2_summary["refundedValidatorsCount"] == 2 - assert no2_summary["stuckPenaltyEndTimestamp"] > chain.time() - - assert staking_module.isOperatorPenaltyCleared(no1_id) == True - assert staking_module.isOperatorPenaltyCleared(no2_id) == False - - # Case 5 - # -- PENALTY_DELAY time passes - # -- A new report arrives - # - Wait for penalty delay time - # - Send report - # - Check rewards shares for "3d" NO and tested NO (should be full for all NOs) - # - Check deposits (should be full for all NOs) - # - Check NOs stats - - # Wait for penalty delay time - chain.sleep(penalty_delay + 1) - chain.mine() - - # Clear penalty for second NO after penalty delay - staking_module.clearNodeOperatorPenalty(no2_id, {"from": impersonated_agent}) - - # shares before report - no1_balance_shares_before = shares_balance(no1_reward_address) - no2_balance_shares_before = shares_balance(no2_reward_address) - no3_balance_shares_before = shares_balance(no3_reward_address) - - # Seventh report - module_shares_dust = shares_balance(staking_module) - (report_tx, extra_report_tx_list) = oracle_report() - distribute_reward(staking_module, stranger.address) - - assert not staking_module.isOperatorPenalized(no1_id) - assert not staking_module.isOperatorPenalized(no2_id) - assert not staking_module.isOperatorPenalized(no3_id) - - # shares after report - no1_balance_shares_after = shares_balance(no1_reward_address) - no2_balance_shares_after = shares_balance(no2_reward_address) - no3_balance_shares_after = shares_balance(no3_reward_address) - - assert staking_module.isOperatorPenaltyCleared(no1_id) - assert staking_module.isOperatorPenaltyCleared(no2_id) - - no1_summary = staking_module.getNodeOperatorSummary(no1_id) - no2_summary = staking_module.getNodeOperatorSummary(no2_id) - - # expected shares - minted_share = ( - calc_module_reward_shares(staking_module.module_id, report_tx.events["TokenRebased"]["sharesMintedAsFees"]) - + module_shares_dust - ) - no1_rewards_after_sixth_report = calc_no_rewards(staking_module, no_id=no1_id, minted_shares=minted_share) - no2_rewards_after_sixth_report = calc_no_rewards(staking_module, no_id=no2_id, minted_shares=minted_share) - no3_rewards_after_sixth_report = calc_no_rewards(staking_module, no_id=no3_id, minted_shares=minted_share) - - # No penalty - # diff by 1 share because of rounding - assert no1_balance_shares_after - no1_balance_shares_before == no1_rewards_after_sixth_report - assert no2_balance_shares_after - no2_balance_shares_before == no2_rewards_after_sixth_report - assert no3_balance_shares_after - no3_balance_shares_before == no3_rewards_after_sixth_report - - assert no1_summary["stuckValidatorsCount"] == 0 - assert no1_summary["totalExitedValidators"] == 7 - assert no1_summary["refundedValidatorsCount"] == 0 - assert no1_summary["stuckPenaltyEndTimestamp"] < chain.time() - - assert no2_summary["stuckValidatorsCount"] == 2 - assert no2_summary["totalExitedValidators"] == 5 - assert no2_summary["refundedValidatorsCount"] == 2 - assert no2_summary["stuckPenaltyEndTimestamp"] < chain.time() - - # Deposit - ( - no1_deposited_keys_before, - no2_deposited_keys_before, - no3_deposited_keys_before, - no1_deposited_keys_after, - no2_deposited_keys_after, - no3_deposited_keys_after, - ) = deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 50, impersonated_agent) - - # check deposit is applied for all NOs - assert no1_deposited_keys_before != no1_deposited_keys_after - assert no2_deposited_keys_before != no2_deposited_keys_after - assert no3_deposited_keys_before != no3_deposited_keys_after + deposit_and_check_keys(staking_module, no1_id, no2_id, no3_id, 50, impersonated_agent) for op_index in (no1_id, no2_id, no3_id): no = staking_module.getNodeOperator(op_index, False) @@ -707,6 +271,8 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et op_index, no["totalDepositedValidators"] + 10, {"from": impersonated_agent} ) + + # Case 6 # -- SActivate target limit for "1st" NO # -- Check deposits @@ -738,6 +304,7 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et assert first_no_summary_after["depositableValidatorsCount"] == 0 assert first_no_summary_after["targetLimitMode"] == 1 + fill_deposit_buffer(50, heuristic=10000) # Deposit ( no1_deposited_keys_before, @@ -786,17 +353,17 @@ def module_happy_path(staking_module, extra_data_service, impersonated_agent, et @pytest.mark.skip( "TODO: fix the test assumptions about the state of the chain (no exited validators, depositable ETH amount)" ) -def test_node_operator_registry(impersonated_agent, stranger, eth_whale, helpers): +def test_node_operator_registry(impersonated_agent, stranger, helpers): nor = contracts.node_operators_registry nor.module_id = 1 nor.testing_node_operator_ids = [35, 36, 37] - module_happy_path(nor, ExtraDataService(), impersonated_agent, eth_whale, stranger, helpers) + module_happy_path(nor, ExtraDataService(), impersonated_agent, stranger, helpers) -def test_sdvt(impersonated_agent, stranger, eth_whale, helpers): +def test_sdvt(impersonated_agent, stranger, helpers): sdvt = contracts.simple_dvt sdvt.module_id = 2 sdvt.testing_node_operator_ids = [0, 1, 2] fill_simple_dvt_ops_keys(stranger, 3, 100) - module_happy_path(sdvt, ExtraDataService(), impersonated_agent, eth_whale, stranger, helpers) + module_happy_path(sdvt, ExtraDataService(), impersonated_agent, stranger, helpers) diff --git a/tests/regression/test_staking_router_stake_distribution.py b/tests/regression/test_staking_router_stake_distribution.py index 031405a80..116e950d9 100644 --- a/tests/regression/test_staking_router_stake_distribution.py +++ b/tests/regression/test_staking_router_stake_distribution.py @@ -1,7 +1,7 @@ from typing import Dict from utils.config import contracts -from utils.test.csm_helpers import csm_add_node_operator, get_ea_member, fill_csm_operators_with_keys +from utils.test.csm_helpers import csm_add_node_operator, fill_csm_operators_with_keys from utils.test.deposits_helpers import fill_deposit_buffer from utils.test.simple_dvt_helpers import fill_simple_dvt_ops_vetted_keys from utils.test.staking_router_helpers import StakingModuleStatus @@ -29,6 +29,7 @@ def __init__( self.maxDepositsPerBlock = maxDepositsPerBlock self.minDepositBlockDistance = minDepositBlockDistance + def get_modules_info(staking_router): # collect the modules information module_digests = staking_router.getAllStakingModuleDigests() @@ -36,7 +37,8 @@ def get_modules_info(staking_router): for digest in module_digests: (_, _, state, summary) = digest - (id, _, module_fee, treasury_fee, stake_share_limit, status, _, _, _, _, priorityExitShareThreshold, maxDepositsPerBlock, minDepositBlockDistance) = state + (id, _, module_fee, treasury_fee, stake_share_limit, status, _, _, _, _, priorityExitShareThreshold, + maxDepositsPerBlock, minDepositBlockDistance) = state (exited_keys, deposited_keys, depositable_keys) = summary if status != StakingModuleStatus.Active.value: # reset depositable keys in case of module is inactivated @@ -65,7 +67,6 @@ def prep_modules_info(modules: Dict[int, Module]): def calc_allocation(modules: Dict[int, Module], keys_to_allocate: int, ignore_depositable: bool = False): - total_active_keys = prep_modules_info(modules) # simulate target share distribution # https://github.com/lidofinance/lido-dao/blob/331ecec7fe3c8d57841fd73ccca7fb1cc9bc174e/contracts/0.8.9/StakingRouter.sol#L1266-L1268 @@ -110,8 +111,8 @@ def assure_depositable_keys(stranger): if not modules[2].depositable_keys: fill_simple_dvt_ops_vetted_keys(stranger, 3, 5) if not modules[3].depositable_keys: - address, proof = get_ea_member() - csm_add_node_operator(contracts.csm, contracts.cs_accounting, address, proof, curve_id=contracts.cs_early_adoption.CURVE_ID()) + csm_add_node_operator(contracts.csm, contracts.cs_permissionless_gate, contracts.cs_accounting, stranger) + def test_stake_distribution(stranger): """ diff --git a/tests/regression/test_validator_exit_bus_happy_path.py b/tests/regression/test_validator_exit_bus_happy_path.py index 3adfc4b96..994e9d119 100644 --- a/tests/regression/test_validator_exit_bus_happy_path.py +++ b/tests/regression/test_validator_exit_bus_happy_path.py @@ -96,9 +96,6 @@ def test_send_validator_to_exit(helpers, web3): total_requests_after = contracts.validators_exit_bus_oracle.getTotalRequestsProcessed() last_processing_ref_slot_after = contracts.validators_exit_bus_oracle.getLastProcessingRefSlot() processing_state_after = ProcessingState(*contracts.validators_exit_bus_oracle.getProcessingState()) - last_requested_validator_index_after = contracts.validators_exit_bus_oracle.getLastRequestedValidatorIndices( - module_id, [no_id] - ) # Asserts helpers.assert_single_event_named("ProcessingStarted", tx, {"refSlot": ref_slot, "hash": report_hash_hex}) @@ -116,7 +113,6 @@ def test_send_validator_to_exit(helpers, web3): assert total_requests_after == total_requests_before + 1 - assert last_requested_validator_index_after == (unreachable_cl_validator_index,) assert last_processing_ref_slot_after != last_processing_ref_slot_before assert last_processing_ref_slot_after == ref_slot @@ -179,15 +175,6 @@ def test_send_multiple_validators_to_exit(helpers, web3, stranger): total_requests_after = contracts.validators_exit_bus_oracle.getTotalRequestsProcessed() last_processing_ref_slot_after = contracts.validators_exit_bus_oracle.getLastProcessingRefSlot() processing_state_after = ProcessingState(*contracts.validators_exit_bus_oracle.getProcessingState()) - first_last_requested_validator_index_after = contracts.validators_exit_bus_oracle.getLastRequestedValidatorIndices( - first_module_id, [first_no_id] - ) - second_last_requested_validator_index_after = contracts.validators_exit_bus_oracle.getLastRequestedValidatorIndices( - second_module_id, [second_no_id] - ) - third_last_requested_validator_index_after = contracts.validators_exit_bus_oracle.getLastRequestedValidatorIndices( - third_module_id, [third_no_id] - ) # Asserts helpers.assert_single_event_named("ProcessingStarted", tx, {"refSlot": ref_slot, "hash": report_hash_hex}) @@ -218,9 +205,6 @@ def test_send_multiple_validators_to_exit(helpers, web3, stranger): assert total_requests_after == total_requests_before + 3 - assert first_last_requested_validator_index_after == (first_validator_index,) - assert second_last_requested_validator_index_after == (second_validator_index,) - assert third_last_requested_validator_index_after == (third_validator_index,) assert last_processing_ref_slot_after != last_processing_ref_slot_before assert last_processing_ref_slot_after == ref_slot diff --git a/tests/snapshot/test_dsm.py b/tests/snapshot/test_dsm.py index 98bcbf305..6de8a2ed9 100644 --- a/tests/snapshot/test_dsm.py +++ b/tests/snapshot/test_dsm.py @@ -147,12 +147,10 @@ def _snap(dsm): "getMaxOperatorsPerUnvetting": dsm.getMaxOperatorsPerUnvetting(), "getLastDepositBlock": dsm.getLastDepositBlock(), "isDepositsPaused": dsm.isDepositsPaused(), - # NOTE: unchecked views - # Implementation address changes - # "address": dsm.address, + "address": dsm.address, # The following two fields are constant and built differently across versions - # "ATTEST_MESSAGE_PREFIX": dsm.ATTEST_MESSAGE_PREFIX(), - # "PAUSE_MESSAGE_PREFIX": dsm.PAUSE_MESSAGE_PREFIX(), + "ATTEST_MESSAGE_PREFIX": dsm.ATTEST_MESSAGE_PREFIX(), + "PAUSE_MESSAGE_PREFIX": dsm.PAUSE_MESSAGE_PREFIX(), } return _snap diff --git a/tests/snapshot/test_first_slots.py b/tests/snapshot/test_first_slots.py index 3f419cb20..390eb573d 100644 --- a/tests/snapshot/test_first_slots.py +++ b/tests/snapshot/test_first_slots.py @@ -108,7 +108,6 @@ def _snap(): contracts.easy_track, contracts.wsteth, contracts.csm, - contracts.cs_early_adoption, contracts.cs_accounting, contracts.cs_fee_distributor, contracts.cs_fee_oracle, diff --git a/tests/snapshot/test_lido_snapshot.py b/tests/snapshot/test_lido_snapshot.py index 80a70a4ab..abfd36996 100644 --- a/tests/snapshot/test_lido_snapshot.py +++ b/tests/snapshot/test_lido_snapshot.py @@ -230,24 +230,24 @@ def test_lido_dao_ops_snapshot(sandwich_upgrade: SandwichFn): def get_actions(from_address: Account | None = None): return ( - _call(lido.pauseStaking, {"from": from_address}), - _call(lido.stop, {"from": from_address}), - _call(lido.resumeStaking, {"from": from_address}), - _call(lido.pauseStaking, {"from": from_address}), - _call(lido.removeStakingLimit, {"from": from_address}), - _call(lido.resumeStaking, {"from": from_address}), - _call( - lido.receiveELRewards, - { - "from": el_vault, - "value": _1ETH, - }, - ), - _call(lido.pauseStaking, {"from": from_address}), - _call(lido.setStakingLimit, 17, 3, {"from": from_address}), - _call(lido.resume, {"from": from_address}), - _call(lido.stop, {"from": from_address}), - ) + _call(lido.pauseStaking, {"from": from_address}), + _call(lido.stop, {"from": from_address}), + _call(lido.resumeStaking, {"from": from_address}), + _call(lido.pauseStaking, {"from": from_address}), + _call(lido.removeStakingLimit, {"from": from_address}), + _call(lido.resumeStaking, {"from": from_address}), + _call( + lido.receiveELRewards, + { + "from": el_vault, + "value": _1ETH, + }, + ), + _call(lido.pauseStaking, {"from": from_address}), + _call(lido.setStakingLimit, 17, 3, {"from": from_address}), + _call(lido.resume, {"from": from_address}), + _call(lido.stop, {"from": from_address}), + ) stacks = sandwich_upgrade(get_actions) _stacks_equal(stacks) @@ -406,11 +406,6 @@ def _actions_snaps(builder_arg: Account | None): func=repr(action_fn), ) - with _chain_snapshot(): - v1_frames = tuple(_actions_snaps(contracts.voting)) - - execute_vote_and_process_dg_proposals(helpers, vote_ids_from_env, dg_proposal_ids_from_env) - contracts.acl.grantPermission( contracts.agent, contracts.lido, @@ -435,7 +430,12 @@ def _actions_snaps(builder_arg: Account | None): contracts.lido.STAKING_CONTROL_ROLE(), {"from": contracts.agent}, ) - + + with _chain_snapshot(): + v1_frames = tuple(_actions_snaps(contracts.agent)) + + execute_vote_and_process_dg_proposals(helpers, vote_ids_from_env, dg_proposal_ids_from_env) + v2_frames = tuple(_actions_snaps(contracts.agent)) return v1_frames, v2_frames diff --git a/tests/snapshot/test_node_operators_registry.py b/tests/snapshot/test_node_operators_registry.py index 1459cc6d4..5e26d8981 100644 --- a/tests/snapshot/test_node_operators_registry.py +++ b/tests/snapshot/test_node_operators_registry.py @@ -7,10 +7,7 @@ from brownie.convert.datatypes import ReturnValue from tests.snapshot.utils import get_slot -from utils.config import ( - contracts, - DEPOSIT_SECURITY_MODULE -) +from utils.config import contracts, DEPOSIT_SECURITY_MODULE from utils.mainnet_fork import chain_snapshot from utils.test.snapshot_helpers import dict_zip from utils.test.governance_helpers import execute_vote_and_process_dg_proposals @@ -30,7 +27,13 @@ def grant_roles(voting_eoa, agent_eoa): contracts.voting, contracts.node_operators_registry, convert.to_uint(Web3.keccak(text="MANAGE_NODE_OPERATOR_ROLE")), - {"from": contracts.voting}, + {"from": agent_eoa}, + ) + contracts.acl.grantPermission( + agent_eoa, + contracts.node_operators_registry, + convert.to_uint(Web3.keccak(text="SET_NODE_OPERATOR_LIMIT_ROLE")), + {"from": agent_eoa}, ) @@ -101,7 +104,7 @@ def create_actions(dsm_eoa, manager_eoa): new_node_operator["id"], new_node_operator["staking_limit"], 1, - {"from": manager_eoa}, + {"from": new_node_operator["reward_address"]}, ), "deactivate_node_operator": lambda: contracts.node_operators_registry.deactivateNodeOperator( new_node_operator["id"], {"from": manager_eoa} @@ -121,7 +124,9 @@ def create_actions(dsm_eoa, manager_eoa): make_snapshot(contracts.node_operators_registry) with chain_snapshot(): - snapshot_before_update = run_scenario(actions=create_actions(new_deposit_security_module_eoa, voting_eoa), snapshooter=make_snapshot) + snapshot_before_update = run_scenario( + actions=create_actions(new_deposit_security_module_eoa, agent_eoa), snapshooter=make_snapshot + ) with chain_snapshot(): execute_vote_and_process_dg_proposals(helpers, vote_ids_from_env, dg_proposal_ids_from_env) @@ -130,22 +135,24 @@ def create_actions(dsm_eoa, manager_eoa): contracts.agent, contracts.node_operators_registry, convert.to_uint(Web3.keccak(text="MANAGE_NODE_OPERATOR_ROLE")), - {"from": contracts.agent} + {"from": contracts.agent}, ) contracts.acl.grantPermission( contracts.agent, contracts.node_operators_registry, convert.to_uint(Web3.keccak(text="SET_NODE_OPERATOR_LIMIT_ROLE")), - {"from": contracts.agent} + {"from": contracts.agent}, ) contracts.acl.grantPermission( contracts.agent, contracts.node_operators_registry, convert.to_uint(Web3.keccak(text="MANAGE_SIGNING_KEYS")), - {"from": contracts.agent} + {"from": contracts.agent}, ) - snapshot_after_update = run_scenario(actions=create_actions(new_deposit_security_module_eoa, agent_eoa), snapshooter=make_snapshot) + snapshot_after_update = run_scenario( + actions=create_actions(new_deposit_security_module_eoa, agent_eoa), snapshooter=make_snapshot + ) assert snapshot_before_update.keys() == snapshot_after_update.keys() @@ -249,6 +256,7 @@ def assert_rewards_distribution(before, after): for i in range(after["active_node_operators_count"]): assert rewards_distribution_before["recipients"][i] == rewards_distribution_after["recipients"][i] + assert almost_eq( rewards_distribution_before["shares"][i], rewards_distribution_after["shares"][i], diff --git a/utils/config.py b/utils/config.py index a8877702b..573bd42b2 100644 --- a/utils/config.py +++ b/utils/config.py @@ -210,11 +210,6 @@ def simple_dvt(self) -> interface.SimpleDVT: def csm(self) -> interface.CSModule: return interface.CSModule(CSM_ADDRESS) - @property - def cs_early_adoption(self) -> interface.CSEarlyAdoption: - """Deprecated""" - return interface.CSEarlyAdoption(CS_EARLY_ADOPTION_ADDRESS) - @property def cs_permissionless_gate(self) -> interface.CSPermissionlessGate: return interface.CSPermissionlessGate(CS_PERMISSIONLESS_GATE_ADDRESS) @@ -227,6 +222,10 @@ def cs_vetted_gate(self) -> interface.CSVettedGate: def cs_accounting(self) -> interface.CSAccounting: return interface.CSAccounting(CS_ACCOUNTING_ADDRESS) + @property + def cs_parameters_registry(self) -> interface.CSParametersRegistry: + return interface.CSParametersRegistry(CS_PARAMS_REGISTRY_ADDRESS) + @property def cs_fee_distributor(self) -> interface.CSFeeDistributor: return interface.CSFeeDistributor(CS_FEE_DISTRIBUTOR_ADDRESS) @@ -240,16 +239,12 @@ def csm_hash_consensus(self) -> interface.CSHashConsensus: return interface.CSHashConsensus(CS_ORACLE_HASH_CONSENSUS_ADDRESS) @property - def cs_verifier(self) -> interface.CSVerifier: - return interface.CSVerifier(CS_VERIFIER_ADDRESS) - - @property - def cs_verifier_v2(self) -> interface.CSVerifierV2: + def cs_verifier(self) -> interface.CSVerifierV2: return interface.CSVerifierV2(CS_VERIFIER_V2_ADDRESS) @property def cs_exit_penalties(self) -> interface.CSExitPenalties: - return interface.CSExitPenalties(CS_EXIT_PENALTIES) + return interface.CSExitPenalties(CS_EXIT_PENALTIES_ADDRESS) @property def cs_ejector(self) -> interface.CSEjector: @@ -403,6 +398,10 @@ def wsteth(self) -> interface.WstETH: def gate_seal(self) -> interface.GateSeal: return interface.GateSeal(GATE_SEAL) + @property + def veb_twg_gate_seal(self) -> interface.GateSeal: + return interface.GateSeal(VEB_TWG_GATE_SEAL) + @property def evm_script_registry(self) -> interface.EVMScriptRegistry: return interface.EVMScriptRegistry(ARAGON_EVMSCRIPT_REGISTRY) @@ -455,6 +454,10 @@ def emergency_protected_timelock(self) -> interface.EmergencyProtectedTimelock: def emergency_governance(self) -> interface.EmergencyGovernance: return interface.EmergencyGovernance(DAO_EMERGENCY_GOVERNANCE) + @property + def triggerable_withdrawals_gateway(self) -> interface.TriggerableWithdrawalsGateway: + return interface.TriggerableWithdrawalsGateway(TRIGGERABLE_WITHDRAWALS_GATEWAY) + def __getattr__(name: str) -> Any: if name == "contracts": diff --git a/utils/dsm.py b/utils/dsm.py index 9b28aed29..a0f6d47fc 100644 --- a/utils/dsm.py +++ b/utils/dsm.py @@ -126,3 +126,16 @@ def set_single_guardian(dsm, agent, new_guardian): assert len(dsm.getGuardians()) == 1 assert dsm.isGuardian(new_guardian.address) + + +def encode_add_guardian(dsm, guardian_address, quorum_size): + return ( + dsm.address, + dsm.addGuardian.encode_input(guardian_address, quorum_size) + ) + +def encode_remove_guardian(dsm, guardian_address, quorum_size): + return ( + dsm.address, + dsm.removeGuardian.encode_input(guardian_address, quorum_size) + ) \ No newline at end of file diff --git a/utils/dual_governance.py b/utils/dual_governance.py index 4f9636eb3..69beabce2 100644 --- a/utils/dual_governance.py +++ b/utils/dual_governance.py @@ -103,13 +103,13 @@ def process_pending_proposals(): if is_proposal_executed(last_proposal_id): return - + current_proposal_id = last_proposal_id while is_proposal_executed(current_proposal_id): current_proposal_id -= 1 if current_proposal_id == 1: break - + process_proposals(list(range(current_proposal_id, last_proposal_id + 1))) @@ -139,26 +139,57 @@ def wait_for_normal_state(stranger): if remaining_time > 0: chain.sleep(remaining_time + 1) - + contracts.dual_governance.activateNextState({"from": stranger}) +def wait_for_time_window(from_hour_utc: int, to_hour_utc: int): + """Wait until current time is within specified UTC hour window""" + current_time = chain.time() + seconds_per_day = 24 * 60 * 60 + + # Get current UTC hour + current_utc_seconds = current_time % seconds_per_day + current_utc_hour = current_utc_seconds // 3600 + + # Check if we're already in the window + if from_hour_utc <= current_utc_hour < to_hour_utc: + print(f"Already in time window ({from_hour_utc}:00-{to_hour_utc}:00 UTC)") + return + + # Calculate when to sleep until + day_start = current_time - current_utc_seconds + window_start = day_start + from_hour_utc * 60 * 60 + window_end = day_start + to_hour_utc * 60 * 60 + + # If we're past today's window, wait for tomorrow's window + if current_time >= window_end: + target_time = window_start + seconds_per_day + else: + # Wait for today's window + target_time = window_start + + sleep_time = target_time - current_time + 1 + print(f"Sleeping {sleep_time} seconds to reach time window ({from_hour_utc}:00-{to_hour_utc}:00 UTC)") + chain.sleep(sleep_time) + + def wait_for_noon_utc_to_satisfy_time_constrains(): current_time = chain.time() noon_offset = 12 * 60 * 60 seconds_per_day = noon_offset * 2 - + day_start = current_time - (current_time % seconds_per_day) today_noon = day_start + noon_offset - + if current_time >= today_noon: target_noon = today_noon + seconds_per_day else: target_noon = today_noon - + chain.sleep(target_noon - current_time) def is_proposal_executed(proposal_id: int) -> bool: (_, _, _, _, proposal_status) = contracts.emergency_protected_timelock.getProposalDetails(proposal_id) - return proposal_status == PROPOSAL_STATUS["executed"] \ No newline at end of file + return proposal_status == PROPOSAL_STATUS["executed"] diff --git a/utils/test/csm_helpers.py b/utils/test/csm_helpers.py index a99bb0be9..db9787d04 100644 --- a/utils/test/csm_helpers.py +++ b/utils/test/csm_helpers.py @@ -1,144 +1,58 @@ -from brownie import ZERO_ADDRESS +from brownie import ZERO_ADDRESS, chain from utils.balance import set_balance_in_wei +from utils.test.easy_track_helpers import _encode_calldata from utils.test.helpers import ETH from utils.test.keys_helpers import random_pubkeys_batch, random_signatures_batch -from utils.config import contracts - -def get_ea_member(): - """ - Random address and proof for EA member - """ - address = "0x00200f4e638e81ebe172daa18c9193a33a50bbbd" - proof = [ - "0x6afd64d1f8e5feed98652d45b758fcbff17eea77665d51f0e531d692a5054756", - "0x52e265b49b47b47690ed87febf862cd32a651b9ab187cad973bc9b77749bb219", - "0x35e699543254ce0682e153798e663901c7b14a637c6823def95687ce98c3bfd2", - "0x90c4d893c062e47126e1fb88c62d7f1addb6787d7681c8b4783e77848fd94ce3", - "0xcc571b6d9faf0a49b61d00cb56d518a9ac9bc61b9ef63c7b6376a3ead99bd455", - "0x190eb8e475726914932a14a9f62b854636a9dcb6323c4d97ac6630fcd29dc33c", - "0x4ac93583eb5d1fb5546b438eac0a489b07b0d62910c4bab3e7b41f0042831d48", - "0xcdc54828056fbe5307ece8e4138766177cd9568ffd68564b37d3deaaf112bb6c", - "0x4d63ec7d0dcc7a38ac4984b6ea8fad8255dfd6419c6c66684e49676d3112e062", - "0x5c39f6b822174cc0267fa29cb2c74340b837859bbc95beca29997689334b4895", - "0x2980e52feb24b69169c73a9618107b58ae5bea120649a045aba137b07e822172", - "0xdbaa84b6f34f08ec11a23797a3497898e75dec4e99bf42d63e7cbfee0dee67d6", - "0xc4556dc19f0330ccc6c929b09a965e05c360d32a5c71c3f64b4123fda973b8dd", - "0x617a04e701d0b1c8e0e96c278ba4caf00e2d787e4287e52fcc4b5f248d89c2b3" - ] - return address, proof - - -def get_ea_members(): - """Each ea member from different source""" - return (( - "0x113e5bA177D3021E4515e847bc4779B074AA0813", [ # good performer - "0xb3f1d62e731a0ac46f103f3423265baaae773036410890c1ee4bc4ba4a5b6806", - "0xdd218546f8029d89f8bb325d50e9a272543ac9642e88d60c6d5b0f1d11db14ea", - "0x82a14915d66df3004c15749f90a53606faaa8adcf890ef9159974a470df16a1f", - "0x9f7ee78a4e733ab2715190ae5481a1456b81b3d5b65a05cd070bcf95fe7a7c92", - "0x68431bdd53ada7d0fcbc0eeae8a7e0f614cbd3da6b54b16214bfedc9e42ea753", - "0x2006bffe956465add92037dd50b5001f7bfdc9ed531fb40b9bbcdff3586ffb63", - "0xbf0015b0b477df4cd5a81eda856a20d65f1a631f033eeb4d630fbebf962a8310", - "0x03c02b7b15ef3c91ae99e86c4c3b1eee48c776e38ffff1a99dcbe4f78942679f", - "0xacbd1f9b565d87a3156b972c1a860a71b5365992f503821166f2c11f591748ec", - "0x8ac7d39a7d9d96d17f5b42f8ef026c44ebb17bd62c995f12e3124b5ca4bfc5e7", - "0x582edbfcd0fb5f0a95caca952bdb943a8cd008c4d114c586e4e03c839bc7c7cd", - "0x772f2c70f39b9a6848799e13c16fe05bdfd1eded3c2b588834bf751b79a9fce5", - "0x3f53e44db24145c061bbbf7d1df796a0ab059b7125c9c2cacf7064bc3904c9d1", - "0x617a04e701d0b1c8e0e96c278ba4caf00e2d787e4287e52fcc4b5f248d89c2b3" - ]), - ("0x6D08b74BD14b2D6Deb468BA31D578a002D0AdDE8", [ # Galxe point holder - "0x6184b17c37f752a58be2c14d26abf9220efff1349fb5c561d9b688b798237d13", - "0xe2d16f320a6de8ef9c8fdca825bad92bb3df1da7995b035d4c0ce2a68cbd3e2a", - "0x35f55c85e9331c8767bf00735389eebc9ba335f52922809cc9cf8d8487646d27", - "0x6442dd1037d0faced9476b99c7f93987326845cd36114be02abebf734759e8a9", - "0xc7f4e2bc84d3a89a6046c9feae416160dad7b28a6209b1e3dff004a3d2b4d0de", - "0xc69995256422fbd2478a7bb8201c777383493e4c1a2fc6a45620341d8108103d", - "0xd703c9506f78ffe85059902bf94a1da7d0efa195424ee10d436af20867700d7c", - "0xfa6b80e968a2f48fc65a45e6763f5a0d470f7640f75edf648d001cb46acefe3c", - "0x9950a0f220017fcd05a338574cbc289a3c00de804ca8d10867a177afd673c347", - "0x83389a6b368766d86b6d57720596f25ff3aeccd4ad21a3b683dbbd231755a2df", - "0x2980e52feb24b69169c73a9618107b58ae5bea120649a045aba137b07e822172", - "0xdbaa84b6f34f08ec11a23797a3497898e75dec4e99bf42d63e7cbfee0dee67d6", - "0xc4556dc19f0330ccc6c929b09a965e05c360d32a5c71c3f64b4123fda973b8dd", - "0x617a04e701d0b1c8e0e96c278ba4caf00e2d787e4287e52fcc4b5f248d89c2b3" - ]), - ("0xe95fb9768cef2893445bc02e7056dead0c32fe6a", [ # dappnode buyer - "0x6fdf504e61ce21367058bc13a34c21f94a4320e29b75c632aa371dd228f2595e", - "0xeeda87c6ce2ef88e9748f7987a64a7147a93be2297f62f44c75f38e5c5756111", - "0x852b5fdd3cf28c632af3270443231205b4d5fa8186b6e241e4f8d3414bfbb540", - "0xa4d359ba49c62fe93c99b49ac4453cf544252e6bf1a42fababa321bb23850163", - "0x8a9297667d1dbe4f17916ff6bc052e58790a3df7703b22baac3f4d224c06a444", - "0x696335ac8a25acf05c2b7b85bd97e0473219f8fff3bc89f49601ba6084f54e51", - "0x6aa7a7a69448a2170b3dc9f6f6227cd0926dd71962e4c15e63448a984369c7a4", - "0x5f87b1e6bfecfd3440114bd9829647532aad1328699af183aeb490d1406003cd", - "0x9d117f35be949e6db5e479949f91cb0710ea3e85be2a58deed5a0b4c05763fe3", - "0x70d5df1f59c0f5fd1667e832f91b8e389adc70f69a520a9f9ca333861bdb27e2", - "0x398e90a61a92850edce556da82fbb16b5f520bcf3fb3c1a5d7cdc6a1baf4883c", - "0xdbaa84b6f34f08ec11a23797a3497898e75dec4e99bf42d63e7cbfee0dee67d6", - "0xc4556dc19f0330ccc6c929b09a965e05c360d32a5c71c3f64b4123fda973b8dd", - "0x617a04e701d0b1c8e0e96c278ba4caf00e2d787e4287e52fcc4b5f248d89c2b3" - ]), - ("0x024813b4972428003c725ea756348dcd79b826e6", [ # obol teche credentials - "0xfc49117ff5d49126e2ed0ee2a6229678604428fc175670aaf6dfcacfba55c414", - "0xa9011da71acb5f3c61c0cc80f5c8b89f916345efb9c149ead010aac852dfbac3", - "0xa0af25f19dde818bb362aae34d967c6d141cfe4b2666a9aeef5fb03cf705ab1b", - "0xb8a34c5bdc302c3944e1f1919f304aa25168e0db81b7e2b67c6afe8a7fa8cc46", - "0x6c209589c3c08d2b8441263874648617f70ebfd255d513840aa191284b5815a9", - "0x45493cc5f6e07014c06f4fe700bc91cedbe7947bdae3d3bdf960ae67abab3adf", - "0xa6df3cbb3e9113c1c429e842c8999b3597d1b6b55c9c979c2703e995b0f762c6", - "0x9e70b4cb13a9517ad1a4fe4920b02abd9eeab2236b9a541e20beaee5557ad7fd", - "0x0a9dc8737db2646bbfc1539e073b563f203e9bfed2aabacfcd03d9d16e8f9739", - "0x2f362f8032842941fe910be787723b082ab7a21effb5cd38022b36c75a103013", - "0x6a5e8cf1bacfe83bee183d9ed803f679d8714103a8106301ad9e355f7790e901", - "0xd001326ce1fa4bfc303be10f953c87ad779c22268ea03d357da5d8e26659e50b", - "0xd597d21fed5e65b2a6de1c6fe70dfdb2df43ab5495a5c0a01c915e60c14c6edb", - "0xf99292f2fccc3f4fa8cef73512bd5f21a46214d922dfed8e8a65f763c13dfb72" - ]), - ("0xe3a2417f8eaafb93a93dc896724e20d0bc1a1feb", [ # rated - "0x2faac9fec99b1a1d464422f5cc64c153514da1d3a438362ef7f1aaa5f585cf65", - "0xf17a0bdf45def725c1ad7bf6c457d4c749705f02ff4282c6739e54dc8965340b", - "0xa0530504a2c0e61ab5de781f0ee4467097595b7a9815b9b2371e33daf920e25c", - "0x1d95475075f06c85ba13b81f01891bde5cf0af4df6f2693b15586884b4a3fac7", - "0x4a8ebe10d4e6f7bb1cadf1e54b58471a6933a62fd7fd6b4750c645f87347c8bd", - "0x96f7f6c9f3b8c3c45392e1598c4ee9ff2aa0eb655bb428c3977e939a8c2cacf5", - "0x404ba635ed5cce8cbc77c4b0eb581c8383e52a7be1507d9fbb053d86fe132fd4", - "0xa680f8f19b75770eee3435719f5731dccd057b968fabd81b40528a9b689a7b6c", - "0x78fe6adcb23cf69e7533e4a3d0558fdc6f0bf13384e85c7679b6d054b05b34ed", - "0xbab879d3c26f5d5e3816a4ce99f35a6ac8139c8df8053608bea4a76951b17e0d", - "0x15b1fc08779715ad26f61b07d0665a82f118104391b56863bd54e6bbe3ec0ff0", - "0xbe7a61521ebadab96f18fdce4dbcfed777f7799c1a02400052ee9dd838ff1ad4", - "0x5894e79a333e76f3e367a65aaad4cc2ca21650c4a532ce89b28009b0d35ca075", - "0xd597d21fed5e65b2a6de1c6fe70dfdb2df43ab5495a5c0a01c915e60c14c6edb", - "0xf99292f2fccc3f4fa8cef73512bd5f21a46214d922dfed8e8a65f763c13dfb72" - ]), - ("0x61ad82d4466437d4cc250a0ceffbcbd7e07b8f96", [ # stake cat - "0xc863e03646d118cf51af3581cacc457f166134a78b3f4253b219e7f694becc50", - "0x52b3bb9a9105a40e8270cd7e6687f3b010213bd9297748d90b7f90dad779defd", - "0x82e0aec8e35aa0c9b8732a77dc5470b13f3d9d36870acec8568ce73807674a15", - "0x096a86c63fccf92230d8d445d7df591d20f9d71ed5c77141e4bb85a47acbb2e3", - "0x4b875dfece281e9d8ab00c0b8544fa7431dc99661c44e0e6cbaad66f942e5c62", - "0x0590fd2e84b7f5a152881a0d17a6fe0732be6ffd020ada4e91693f8e94696cd8", - "0x1f99300883319c93920319ed5159329a98f2efc356165d9587c316abd6d4cbac", - "0x516c84f2139897f30531bd6e08f3372c0a06bdccd9f17ce91bd2565c79b1afca", - "0x5b698237e78d7b2ef3227a5bc652d030bba9bfa8f21aec555eee0b4f65a24b40", - "0x0a125fd7e859f5e8a67214923c80caaa3e48da3ea985ab0d346ed36a0a92989a", - "0xefb4a879db517af0fb7e4f0731a12d8360bc6a155fcfc7546ace79b55cdafa52", - "0xd2af30f01b69d3f2d1d94e5b401418ffa90b566b1450d7b3310a097701ac694a", - "0x769a53742322902c2080251b628f262577d620d70831c142a59b77910c464a63", - "0xf99292f2fccc3f4fa8cef73512bd5f21a46214d922dfed8e8a65f763c13dfb72"]) +from utils.config import contracts, CSM_COMMITTEE_MS, EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY +from utils.test.merkle_tree import ICSTree + + + +def csm_set_ics_tree_members(members): + tree = ICSTree.new(members) + calldata = _encode_calldata(["bytes32", "string"], [tree.root, "0xabc"]) + tx = contracts.easy_track.createMotion(EASYTRACK_CS_SET_VETTED_GATE_TREE_FACTORY, calldata, {"from": CSM_COMMITTEE_MS}) + chain.sleep(60 * 60 * 24 * 3) + chain.mine() + motions = contracts.easy_track.getMotions() + contracts.easy_track.enactMotion( + motions[-1][0], + tx.events["MotionCreated"]["_evmScriptCallData"], + {"from": CSM_COMMITTEE_MS}, + ) + + return tree + + + +def csm_add_node_operator(csm, permissionless_gate, accounting, node_operator, keys_count=5, curve_id=0): + pubkeys_batch = random_pubkeys_batch(keys_count) + signatures_batch = random_signatures_batch(keys_count) + + value = accounting.getBondAmountByKeysCount(keys_count, curve_id) + set_balance_in_wei(node_operator, value + ETH(10)) + + permissionless_gate.addNodeOperatorETH( + keys_count, + pubkeys_batch, + signatures_batch, + (ZERO_ADDRESS, ZERO_ADDRESS, False), + ZERO_ADDRESS, + {"from": node_operator, "value": value} ) + return csm.getNodeOperatorsCount() - 1 -def csm_add_node_operator(csm, accounting, node_operator, proof, keys_count=5, curve_id=0): + +def csm_add_ics_node_operator(csm, vetted_gate, accounting, node_operator, proof, keys_count=5, curve_id=2): pubkeys_batch = random_pubkeys_batch(keys_count) signatures_batch = random_signatures_batch(keys_count) - value = accounting.getBondAmountByKeysCount['uint256,uint256'](keys_count, curve_id) + value = accounting.getBondAmountByKeysCount(keys_count, curve_id) set_balance_in_wei(node_operator, value + ETH(10)) - csm.addNodeOperatorETH( + vetted_gate.addNodeOperatorETH( keys_count, pubkeys_batch, signatures_batch, @@ -162,8 +76,9 @@ def csm_upload_keys(csm, accounting, no_id, keys_count=5): pubkeys_batch = random_pubkeys_batch(keys_batch) signatures_batch = random_signatures_batch(keys_batch) value = accounting.getRequiredBondForNextKeys(no_id, keys_count) - csm.addValidatorKeysETH(no_id, keys_batch, pubkeys_batch, signatures_batch, { - "from": csm.getNodeOperator(no_id)["managerAddress"], + address = csm.getNodeOperator(no_id)["managerAddress"] + csm.addValidatorKeysETH(address, no_id, keys_batch, pubkeys_batch, signatures_batch, { + "from": address, "value": value }) remaining_keys -= keys_batch @@ -179,7 +94,7 @@ def fill_csm_operators_with_keys(target_operators_count, keys_count): assert contracts.csm.getNodeOperator(no_id)["depositableValidatorsCount"] == keys_count while csm_node_operators_before + added_operators_count < target_operators_count: node_operator = f"0xbb{str(added_operators_count).zfill(38)}" - csm_add_node_operator(contracts.csm, contracts.cs_accounting, node_operator, [], keys_count=keys_count) + csm_add_node_operator(contracts.csm, contracts.cs_permissionless_gate, contracts.cs_accounting, node_operator, + keys_count=keys_count) added_operators_count += 1 return csm_node_operators_before, added_operators_count - diff --git a/utils/test/deposits_helpers.py b/utils/test/deposits_helpers.py index b8348523b..56401076f 100644 --- a/utils/test/deposits_helpers.py +++ b/utils/test/deposits_helpers.py @@ -9,9 +9,9 @@ WEI_TOLERANCE = 5 # wei tolerance to avoid rounding issue -def fill_deposit_buffer(deposits_count): +def fill_deposit_buffer(deposits_count, heuristic=1): deposit_size = ETH(32) - depositable_eth = deposits_count * deposit_size + depositable_eth = deposits_count * deposit_size * heuristic cover_wq_demand_and_submit(depositable_eth) diff --git a/utils/test/event_validators/dual_governance.py b/utils/test/event_validators/dual_governance.py index 11d2d5f44..661354e3d 100644 --- a/utils/test/event_validators/dual_governance.py +++ b/utils/test/event_validators/dual_governance.py @@ -24,15 +24,15 @@ def validate_dual_governance_submit_event( if proposal_calls: assert len(event["ProposalSubmitted"][0]["calls"]) == len(proposal_calls), "Wrong callsCount" for i in range(0, len(proposal_calls)): - assert event["ProposalSubmitted"][0]["calls"][i][0] == proposal_calls[i]["target"], "Wrong target" - assert event["ProposalSubmitted"][0]["calls"][i][1] == proposal_calls[i]["value"], "Wrong value" - assert event["ProposalSubmitted"][0]["calls"][i][2] == proposal_calls[i]["data"], "Wrong data" + assert event["ProposalSubmitted"][0]["calls"][i][0] == proposal_calls[i]["target"], f"Wrong target {i}: {event['ProposalSubmitted'][0]['calls'][i][0]} : {proposal_calls[i]['target']}" + assert event["ProposalSubmitted"][0]["calls"][i][1] == proposal_calls[i]["value"], f"Wrong value {i}" + assert event["ProposalSubmitted"][0]["calls"][i][2] == proposal_calls[i]["data"], f'Wrong data {i}' assert event["ProposalSubmitted"][1]["proposalId"] == proposal_id, "Wrong proposalId" assert event["ProposalSubmitted"][1]["proposerAccount"] == proposer, "Wrong proposer" if metadata: - assert event["ProposalSubmitted"][1]["metadata"] == metadata, "Wrong metadata" + assert event["ProposalSubmitted"][1]["metadata"] == metadata, f"Wrong metadata {event['ProposalSubmitted'][1]['metadata']}" if emitted_by is not None: assert len(event["ProposalSubmitted"]) == len(emitted_by), "Wrong emitted_by count" diff --git a/utils/test/extra_data.py b/utils/test/extra_data.py index c2c51227e..5e26f8683 100644 --- a/utils/test/extra_data.py +++ b/utils/test/extra_data.py @@ -14,7 +14,6 @@ class ItemType(Enum): - EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2 UNSUPPORTED = 3 @@ -61,14 +60,15 @@ class ItemPayload: node_operator_ids: Sequence[int] vals_counts: Sequence[int] + class ExtraDataLengths: - NEXT_HASH = 32 ITEM_INDEX = 3 ITEM_TYPE = 2 MODULE_ID = 3 NODE_OPS_COUNT = 8 NODE_OPERATOR_IDS = 8 - STUCK_OR_EXITED_VALS_COUNT = 16 + EXITED_VALS_COUNT = 16 + class ExtraDataService: """ @@ -88,14 +88,12 @@ class ExtraDataService: @classmethod def collect( cls, - stuck_validators: dict[NodeOperatorGlobalIndex, int], exited_validators: dict[NodeOperatorGlobalIndex, int], max_items_count: int, max_no_in_payload_count: int, ) -> ExtraData: - stuck_payloads = cls.build_validators_payloads(stuck_validators, max_no_in_payload_count) exited_payloads = cls.build_validators_payloads(exited_validators, max_no_in_payload_count) - items_count, txs = cls.build_extra_transactions_data(stuck_payloads, exited_payloads, max_items_count) + items_count, txs = cls.build_extra_transactions_data(exited_payloads, max_items_count) extra_data_hash_list, hashed_txs = cls.add_hashes_to_transactions(txs) if items_count: @@ -142,12 +140,10 @@ def build_validators_payloads( @classmethod def build_extra_transactions_data( cls, - stuck_payloads: list[ItemPayload], exited_payloads: list[ItemPayload], max_items_count: int, ) -> tuple[int, list[bytes]]: all_payloads = [ - *[(ItemType.EXTRA_DATA_TYPE_STUCK_VALIDATORS, payload) for payload in stuck_payloads], *[(ItemType.EXTRA_DATA_TYPE_EXITED_VALIDATORS, payload) for payload in exited_payloads], ] @@ -166,7 +162,7 @@ def build_extra_transactions_data( for no_id in payload.node_operator_ids ) tx += b''.join( - count.to_bytes(ExtraDataLengths.STUCK_OR_EXITED_VALS_COUNT, byteorder='big') + count.to_bytes(ExtraDataLengths.EXITED_VALS_COUNT, byteorder='big') for count in payload.vals_counts ) diff --git a/utils/test/merkle_tree.py b/utils/test/merkle_tree.py index 7abfe65a0..ed170293c 100644 --- a/utils/test/merkle_tree.py +++ b/utils/test/merkle_tree.py @@ -12,7 +12,11 @@ Shares: TypeAlias = int NodeOperatorId: TypeAlias = int +Pubkey: TypeAlias = bytes +Strikes: TypeAlias = list[int] RewardTreeLeaf: TypeAlias = tuple[NodeOperatorId, Shares] +StrikesTreeLeaf: TypeAlias = tuple[NodeOperatorId, Pubkey, Strikes] +ICSTreeLeaf: TypeAlias = str class TreeJSONEncoder(json.JSONEncoder): @@ -34,6 +38,9 @@ def find(self, leaf: bytes) -> int: ... @abstractmethod def get_proof(self, index: int) -> Iterable[bytes]: ... + @abstractmethod + def get_multi_proof(self, indices: Collection[int]) -> tuple[Iterable[bytes], Iterable[bool]]: ... + @classmethod @abstractmethod def verify(cls, root: bytes, leaf: bytes, proof: Iterable[bytes]) -> bool: ... @@ -82,10 +89,82 @@ def get_proof(self, index: int) -> Iterable[bytes]: yield self.tree[i - (-1) ** (i % 2)] i = (i - 1) // 2 + def get_multi_proof(self, indices: Collection[int]) -> tuple[Iterable[bytes], Iterable[bool]]: + if not indices: + return [], [] + + indices = sorted(set(indices)) + n = len(self.tree) + leaves_count = (n + 1) // 2 + + proof = [] + flags = [] + + def collect_proof_and_flags(idx: int) -> bool: + if idx >= n: + return False + if idx >= n - leaves_count: + return idx in indices + + left = 2 * idx + 1 + right = 2 * idx + 2 + left_needed = collect_proof_and_flags(left) if left < n else False + right_needed = collect_proof_and_flags(right) if right < n else False + + if left_needed and right_needed: + flags.append(True) + return True + elif left_needed: + if right < n: + proof.append(self.tree[right]) + flags.append(False) + return True + elif right_needed: + if left < n: + proof.append(self.tree[left]) + flags.append(False) + return True + + return False + + collect_proof_and_flags(0) + return proof, flags + @classmethod def verify(cls, root: bytes, leaf: bytes, proof: Iterable[bytes]) -> bool: return reduce(lambda a, b: cls.__hash_node__(a, b), proof, leaf) == root + @classmethod + def verify_multi_proof(cls, root: bytes, leaves: list[bytes], proof: list[bytes], flags: list[bool]) -> bool: + if not leaves: + return True + + if len(leaves) + len(proof) - 1 != len(flags): + return False + + queue = list(leaves) + proof_idx = 0 + + for flag in flags: + if flag: + if len(queue) < 2: + return False + a = queue.pop(0) + b = queue.pop(0) + else: + if len(queue) < 1 or proof_idx >= len(proof): + return False + a = queue.pop(0) + b = proof[proof_idx] + proof_idx += 1 + + queue.append(cls.__hash_node__(a, b)) + + if proof_idx != len(proof): + return False + + return len(queue) == 1 and queue[0] == root + T = TypeVar("T", bound=Iterable) @@ -159,10 +238,10 @@ def __hash_node__(cls, lhs: bytes, rhs: bytes) -> bytes: @dataclass -class Tree: +class RewardsTree: """A wrapper around StandardMerkleTree to cover use cases of the CSM oracle""" - tree: StandardMerkleTree[tuple[int, int]] + tree: StandardMerkleTree[RewardTreeLeaf] @property def root(self) -> HexBytes: @@ -197,3 +276,86 @@ def dump(self) -> Dump[RewardTreeLeaf]: def new(cls, values: Sequence[RewardTreeLeaf]): """Create new instance around the wrapped tree out of the given values""" return cls(StandardMerkleTree(values, ("uint256", "uint256"))) + + +@dataclass +class StrikesTree: + """A wrapper around StandardMerkleTree to cover use cases of the CSM oracle""" + + tree: StandardMerkleTree[StrikesTreeLeaf] + + @property + def root(self) -> HexBytes: + return HexBytes(self.tree.root) + + @classmethod + def decode(cls, content: bytes): + """Restore a tree from a supported binary representation""" + + try: + return cls(StandardMerkleTree.load(json.loads(content))) + except json.JSONDecodeError as e: + raise ValueError("Unsupported tree format") from e + + def encode(self) -> bytes: + """Convert the underlying StandardMerkleTree to a binary representation""" + + return ( + TreeJSONEncoder( + indent=None, + separators=(',', ':'), + sort_keys=True, + ) + .encode(self.dump()) + .encode() + ) + + def dump(self) -> Dump[StrikesTreeLeaf]: + return self.tree.dump() + + @classmethod + def new(cls, values: Sequence[StrikesTreeLeaf]): + """Create new instance around the wrapped tree out of the given values""" + return cls(StandardMerkleTree(values, ("uint256", "bytes", "uint256[]"))) + + +@dataclass +class ICSTree: + """A wrapper around StandardMerkleTree to cover use cases of the CSM ICS Vetted Gate""" + + tree: StandardMerkleTree[ICSTreeLeaf] + + @property + def root(self) -> HexBytes: + return HexBytes(self.tree.root) + + @classmethod + def decode(cls, content: bytes): + """Restore a tree from a supported binary representation""" + + try: + return cls(StandardMerkleTree.load(json.loads(content))) + except json.JSONDecodeError as e: + raise ValueError("Unsupported tree format") from e + + def encode(self) -> bytes: + """Convert the underlying StandardMerkleTree to a binary representation""" + + return ( + TreeJSONEncoder( + indent=None, + separators=(',', ':'), + sort_keys=True, + ) + .encode(self.dump()) + .encode() + ) + + def dump(self) -> Dump[ICSTreeLeaf]: + return self.tree.dump() + + @classmethod + def new(cls, values: Sequence[ICSTreeLeaf]): + """Create new instance around the wrapped tree out of the given values""" + values = [[value] for value in values] + return cls(StandardMerkleTree(values, ("address",))) diff --git a/utils/test/oracle_report_helpers.py b/utils/test/oracle_report_helpers.py index 7ace0ca5e..6b4598493 100644 --- a/utils/test/oracle_report_helpers.py +++ b/utils/test/oracle_report_helpers.py @@ -11,12 +11,12 @@ from utils.config import contracts, AO_CONSENSUS_VERSION from utils.test.exit_bus_data import encode_data from utils.test.helpers import ETH, GWEI, eth_balance -from utils.test.merkle_tree import Tree +from utils.test.merkle_tree import RewardsTree ZERO_HASH = bytes([0] * 32) ZERO_BYTES32 = HexBytes(ZERO_HASH) ONE_DAY = 1 * 24 * 60 * 60 -SHARE_RATE_PRECISION = 10**27 +SHARE_RATE_PRECISION = 10 ** 27 EXTRA_DATA_FORMAT_EMPTY = 0 EXTRA_DATA_FORMAT_LIST = 1 @@ -108,14 +108,14 @@ def prepare_exit_bus_report(validators_to_exit, ref_slot): return report, report_hash -def prepare_csm_report(node_operators_rewards: dict, ref_slot): +def prepare_csm_report(node_operators_rewards: dict, ref_slot, distributed_shares): consensus_version = contracts.cs_fee_oracle.getConsensusVersion() shares = node_operators_rewards.copy() if len(shares) < 2: # put a stone - shares[2**64 - 1] = 0 + shares[2 ** 64 - 1] = 0 - tree = Tree.new(tuple((no_id, amount) for (no_id, amount) in shares.items())) + tree = RewardsTree.new(tuple((no_id, amount) for (no_id, amount) in shares.items())) # semi-random values log_cid = web3.keccak(tree.root) tree_cid = web3.keccak(log_cid) @@ -126,7 +126,10 @@ def prepare_csm_report(node_operators_rewards: dict, ref_slot): tree.root, str(tree_cid), str(log_cid), - sum(shares.values()), + distributed_shares, + 0, # rebate + HexBytes(ZERO_HASH), # strikesTreeRoot + "", # strikesTreeCid ) report_data = encode_data_from_abi(report, contracts.cs_fee_oracle.abi, "submitReportData") report_hash = web3.keccak(report_data) @@ -231,7 +234,7 @@ def push_oracle_report( extraDataItemsCount=extraDataItemsCount, ) submitter = reach_consensus(refSlot, hash, consensusVersion, contracts.hash_consensus_for_accounting_oracle, silent) - accounts[0].transfer(submitter, 10**19) + accounts[0].transfer(submitter, 10 ** 19) # print(contracts.oracle_report_sanity_checker.getOracleReportLimits()) report_tx = contracts.accounting_oracle.submitReportData(items, oracleVersion, {"from": submitter}) if not silent: @@ -287,7 +290,7 @@ def simulate_report( # The code is taken from the current production `lido-oracle` implementation # source: https://github.com/lidofinance/lido-oracle/blob/da393bf06250344a4d06dce6d1ac6a3ddcb9c7a3/src/providers/execution/contracts/lido.py#L93-L95 "stateDiff": { - override_slot: refSlot, + override_slot: '0x' + refSlot.to_bytes(32, "big").hex(), }, }, } @@ -347,7 +350,9 @@ def wait_to_next_available_report_time(consensus_contract): (refSlot, _) = consensus_contract.getCurrentFrame() else: raise - time = web3.eth.get_block("latest").timestamp + + # Use chain.time() instead of block timestamp for consistency + time = chain.time() (_, EPOCHS_PER_FRAME, _) = consensus_contract.getFrameConfig() frame_start_with_offset = GENESIS_TIME + (refSlot + SLOTS_PER_EPOCH * EPOCHS_PER_FRAME + 1) * SECONDS_PER_SLOT chain.sleep(frame_start_with_offset - time) diff --git a/utils/test/staking_router_helpers.py b/utils/test/staking_router_helpers.py index c91d50cab..ff76859ce 100644 --- a/utils/test/staking_router_helpers.py +++ b/utils/test/staking_router_helpers.py @@ -2,11 +2,15 @@ from utils.config import contracts from enum import IntEnum +TOTAL_BASIS_POINTS = 10_000 + + class StakingModuleStatus(IntEnum): Active = 0 DepositsPaused = 1 Stopped = 2 + def set_staking_module_status(module_id, staking_module_status: StakingModuleStatus): contracts.staking_router.setStakingModuleStatus(module_id, staking_module_status, {"from": contracts.agent}) @@ -16,8 +20,8 @@ def increase_staking_module_share(module_id, share_multiplier): contracts.staking_router.updateStakingModule( module_id, - module["stakeShareLimit"] * share_multiplier, - module["priorityExitShareThreshold"] * share_multiplier, + min(module["stakeShareLimit"] * share_multiplier, TOTAL_BASIS_POINTS), + min(module["priorityExitShareThreshold"] * share_multiplier, TOTAL_BASIS_POINTS), module["stakingModuleFee"], module["treasuryFee"], module["maxDepositsPerBlock"], diff --git a/utils/test/tx_tracing_helpers.py b/utils/test/tx_tracing_helpers.py index 1735f0294..a734350d0 100644 --- a/utils/test/tx_tracing_helpers.py +++ b/utils/test/tx_tracing_helpers.py @@ -54,13 +54,13 @@ def count_vote_items_by_events(tx: TransactionReceipt, voting_addr: str) -> int: def display_voting_events(tx: TransactionReceipt) -> None: - dict_events = EventDict(tx_events_from_trace(tx)) + dict_events = EventDict(tx_events_from_receipt(tx)) groups = [_vote_item_group, _service_item_group] display_tx_events(dict_events, "Events registered during the vote execution", groups) def display_dg_events(tx: TransactionReceipt) -> None: - dict_events = EventDict(tx_events_from_trace(tx)) + dict_events = EventDict(tx_events_from_receipt(tx)) groups = [_dg_item_group, _service_item_group] display_tx_events(dict_events, "Events registered during the proposal execution", groups) @@ -72,7 +72,7 @@ def add_event_emitter(event): def group_voting_events(tx: TransactionReceipt) -> List[EventDict]: - events = tx_events_from_trace(tx) + events = tx_events_from_receipt(tx) # manually add event emitter address because it is dropped by EventDict class events = [add_event_emitter(e) for e in events] @@ -90,7 +90,7 @@ def group_voting_events(tx: TransactionReceipt) -> List[EventDict]: return ret def group_dg_events(tx: TransactionReceipt) -> List[EventDict]: - events = tx_events_from_trace(tx) + events = tx_events_from_receipt(tx) # manually add event emitter address because it is dropped by EventDict class events = [add_event_emitter(e) for e in events] @@ -117,13 +117,6 @@ def group_dg_events(tx: TransactionReceipt) -> List[EventDict]: ) -def display_dg_events(tx: TransactionReceipt) -> None: - dict_events = EventDict(tx_events_from_trace(tx)) - groups = [_dg_item_group, _service_item_group] - - display_tx_events(dict_events, "Events registered during the proposal execution", groups) - - def group_voting_events_from_receipt(tx: TransactionReceipt) -> List[EventDict]: events = tx_events_from_receipt(tx) diff --git a/yarn.lock b/yarn.lock index 8ac5bb2a8..ad64354e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,134 +3,139 @@ "@adraffy/ens-normalize@^1.8.8": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" - integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== - -"@esbuild/aix-ppc64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz#4e0f91776c2b340e75558f60552195f6fad09f18" - integrity sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA== - -"@esbuild/android-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz#bc766407f1718923f6b8079c8c61bf86ac3a6a4f" - integrity sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg== - -"@esbuild/android-arm@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.5.tgz#4290d6d3407bae3883ad2cded1081a234473ce26" - integrity sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA== - -"@esbuild/android-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.5.tgz#40c11d9cbca4f2406548c8a9895d321bc3b35eff" - integrity sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw== - -"@esbuild/darwin-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz#49d8bf8b1df95f759ac81eb1d0736018006d7e34" - integrity sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ== - -"@esbuild/darwin-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz#e27a5d92a14886ef1d492fd50fc61a2d4d87e418" - integrity sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ== - -"@esbuild/freebsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz#97cede59d638840ca104e605cdb9f1b118ba0b1c" - integrity sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw== - -"@esbuild/freebsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz#71c77812042a1a8190c3d581e140d15b876b9c6f" - integrity sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw== - -"@esbuild/linux-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz#f7b7c8f97eff8ffd2e47f6c67eb5c9765f2181b8" - integrity sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg== - -"@esbuild/linux-arm@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz#2a0be71b6cd8201fa559aea45598dffabc05d911" - integrity sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw== - -"@esbuild/linux-ia32@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz#763414463cd9ea6fa1f96555d2762f9f84c61783" - integrity sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA== - -"@esbuild/linux-loong64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz#428cf2213ff786a502a52c96cf29d1fcf1eb8506" - integrity sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg== - -"@esbuild/linux-mips64el@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz#5cbcc7fd841b4cd53358afd33527cd394e325d96" - integrity sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg== - -"@esbuild/linux-ppc64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz#0d954ab39ce4f5e50f00c4f8c4fd38f976c13ad9" - integrity sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ== - -"@esbuild/linux-riscv64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz#0e7dd30730505abd8088321e8497e94b547bfb1e" - integrity sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA== - -"@esbuild/linux-s390x@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz#5669af81327a398a336d7e40e320b5bbd6e6e72d" - integrity sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ== - -"@esbuild/linux-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz#b2357dd153aa49038967ddc1ffd90c68a9d2a0d4" - integrity sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw== - -"@esbuild/netbsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz#53b4dfb8fe1cee93777c9e366893bd3daa6ba63d" - integrity sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw== - -"@esbuild/netbsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz#a0206f6314ce7dc8713b7732703d0f58de1d1e79" - integrity sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ== - -"@esbuild/openbsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz#2a796c87c44e8de78001d808c77d948a21ec22fd" - integrity sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw== - -"@esbuild/openbsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz#28d0cd8909b7fa3953af998f2b2ed34f576728f0" - integrity sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg== - -"@esbuild/sunos-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz#a28164f5b997e8247d407e36c90d3fd5ddbe0dc5" - integrity sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA== - -"@esbuild/win32-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz#6eadbead38e8bd12f633a5190e45eff80e24007e" - integrity sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw== - -"@esbuild/win32-ia32@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz#bab6288005482f9ed2adb9ded7e88eba9a62cc0d" - integrity sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ== - -"@esbuild/win32-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz#7fc114af5f6563f19f73324b5d5ff36ece0803d1" - integrity sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g== + version "1.11.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + +"@esbuild/aix-ppc64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz#ee6b7163a13528e099ecf562b972f2bcebe0aa97" + integrity sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw== + +"@esbuild/android-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz#115fc76631e82dd06811bfaf2db0d4979c16e2cb" + integrity sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg== + +"@esbuild/android-arm@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.10.tgz#8d5811912da77f615398611e5bbc1333fe321aa9" + integrity sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w== + +"@esbuild/android-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.10.tgz#e3e96516b2d50d74105bb92594c473e30ddc16b1" + integrity sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg== + +"@esbuild/darwin-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz#6af6bb1d05887dac515de1b162b59dc71212ed76" + integrity sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA== + +"@esbuild/darwin-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz#99ae82347fbd336fc2d28ffd4f05694e6e5b723d" + integrity sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg== + +"@esbuild/freebsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz#0c6d5558a6322b0bdb17f7025c19bd7d2359437d" + integrity sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg== + +"@esbuild/freebsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz#8c35873fab8c0857a75300a3dcce4324ca0b9844" + integrity sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA== + +"@esbuild/linux-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz#3edc2f87b889a15b4cedaf65f498c2bed7b16b90" + integrity sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ== + +"@esbuild/linux-arm@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz#86501cfdfb3d110176d80c41b27ed4611471cde7" + integrity sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg== + +"@esbuild/linux-ia32@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz#e6589877876142537c6864680cd5d26a622b9d97" + integrity sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ== + +"@esbuild/linux-loong64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz#11119e18781f136d8083ea10eb6be73db7532de8" + integrity sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg== + +"@esbuild/linux-mips64el@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz#3052f5436b0c0c67a25658d5fc87f045e7def9e6" + integrity sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA== + +"@esbuild/linux-ppc64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz#2f098920ee5be2ce799f35e367b28709925a8744" + integrity sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA== + +"@esbuild/linux-riscv64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz#fa51d7fd0a22a62b51b4b94b405a3198cf7405dd" + integrity sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA== + +"@esbuild/linux-s390x@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz#a27642e36fc282748fdb38954bd3ef4f85791e8a" + integrity sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew== + +"@esbuild/linux-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz#9d9b09c0033d17529570ced6d813f98315dfe4e9" + integrity sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA== + +"@esbuild/netbsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz#25c09a659c97e8af19e3f2afd1c9190435802151" + integrity sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A== + +"@esbuild/netbsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz#7fa5f6ffc19be3a0f6f5fd32c90df3dc2506937a" + integrity sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig== + +"@esbuild/openbsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz#8faa6aa1afca0c6d024398321d6cb1c18e72a1c3" + integrity sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw== + +"@esbuild/openbsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz#a42979b016f29559a8453d32440d3c8cd420af5e" + integrity sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw== + +"@esbuild/openharmony-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz#fd87bfeadd7eeb3aa384bbba907459ffa3197cb1" + integrity sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag== + +"@esbuild/sunos-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz#3a18f590e36cb78ae7397976b760b2b8c74407f4" + integrity sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ== + +"@esbuild/win32-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz#e71741a251e3fd971408827a529d2325551f530c" + integrity sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw== + +"@esbuild/win32-ia32@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz#c6f010b5d3b943d8901a0c87ea55f93b8b54bf94" + integrity sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw== + +"@esbuild/win32-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz#e4b3e255a1b4aea84f6e1d2ae0b73f826c3785bd" + integrity sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw== "@ethereumjs/rlp@^4.0.1": version "4.0.1" @@ -382,58 +387,63 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== -"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": +"@noble/secp256k1@1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== -"@nomicfoundation/edr-darwin-arm64@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.0.tgz#fa791451c5ce2acf6634143bca9fe8f1b5c66603" - integrity sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw== - -"@nomicfoundation/edr-darwin-x64@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.0.tgz#b1aaf0bfb331f6d136a92cbe31f184e2209e7a4f" - integrity sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A== - -"@nomicfoundation/edr-linux-arm64-gnu@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.0.tgz#fef6763c5d42bb68b4fc95df45c4745a0e31df93" - integrity sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA== - -"@nomicfoundation/edr-linux-arm64-musl@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.0.tgz#ef89d5d2aefc1f8d4f7c699c59b8897a645d33eb" - integrity sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ== - -"@nomicfoundation/edr-linux-x64-gnu@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.0.tgz#97432126110aa805b761d4743ab158698cae6d66" - integrity sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ== - -"@nomicfoundation/edr-linux-x64-musl@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.0.tgz#7605fddbada22dfdd14b15f4ac562014d9c82332" - integrity sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg== - -"@nomicfoundation/edr-win32-x64-msvc@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.0.tgz#6766175f3ec47bfbda0429ca00fed4ae5632a3c4" - integrity sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q== - -"@nomicfoundation/edr@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.11.0.tgz#d8b0ba4dfd7d93b9c54762e72eb9cd4e8244ce46" - integrity sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw== - dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.11.0" - "@nomicfoundation/edr-darwin-x64" "0.11.0" - "@nomicfoundation/edr-linux-arm64-gnu" "0.11.0" - "@nomicfoundation/edr-linux-arm64-musl" "0.11.0" - "@nomicfoundation/edr-linux-x64-gnu" "0.11.0" - "@nomicfoundation/edr-linux-x64-musl" "0.11.0" - "@nomicfoundation/edr-win32-x64-msvc" "0.11.0" +"@noble/secp256k1@~1.7.0": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.2.tgz#c2c3343e2dce80e15a914d7442147507f8a98e7f" + integrity sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ== + +"@nomicfoundation/edr-darwin-arm64@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz#d8e2609fc24cf20e75c3782e39cd5a95f7488075" + integrity sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA== + +"@nomicfoundation/edr-darwin-x64@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz#7a9e94cee330269a33c7f1dce267560c7e12dbd3" + integrity sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA== + +"@nomicfoundation/edr-linux-arm64-gnu@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz#cd5ec90c7263045c3dfd0b109c73206e488edc27" + integrity sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ== + +"@nomicfoundation/edr-linux-arm64-musl@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz#ed23df2d9844470f5661716da27d99a72a69e99e" + integrity sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA== + +"@nomicfoundation/edr-linux-x64-gnu@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz#87a62496c2c4b808bc4a9ae96cca1642a21c2b51" + integrity sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw== + +"@nomicfoundation/edr-linux-x64-musl@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz#8cfe408c73bcb9ed5e263910c313866d442f4b48" + integrity sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg== + +"@nomicfoundation/edr-win32-x64-msvc@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz#fb208b94553c7eb22246d73a1ac4de5bfdb97d01" + integrity sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung== + +"@nomicfoundation/edr@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.11.3.tgz#e8b30b868788e45d7a2ee2359a021ef7dcb96952" + integrity sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.11.3" + "@nomicfoundation/edr-darwin-x64" "0.11.3" + "@nomicfoundation/edr-linux-arm64-gnu" "0.11.3" + "@nomicfoundation/edr-linux-arm64-musl" "0.11.3" + "@nomicfoundation/edr-linux-x64-gnu" "0.11.3" + "@nomicfoundation/edr-linux-x64-musl" "0.11.3" + "@nomicfoundation/edr-win32-x64-msvc" "0.11.3" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" @@ -613,23 +623,23 @@ utf-8-validate "6.0.3" "@types/bn.js@^5.1.0": - version "5.1.5" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" - integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.2.0.tgz#4349b9710e98f9ab3cdc50f1c5e4dcbd8ef29c80" + integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== dependencies: "@types/node" "*" -"@types/lru-cache@5.1.1", "@types/lru-cache@^5.1.0": +"@types/lru-cache@5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== "@types/node@*": - version "20.11.16" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.16.tgz#4411f79411514eb8e2926f036c86c9f0e4ec6708" - integrity sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ== + version "24.5.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.5.2.tgz#52ceb83f50fe0fcfdfbd2a9fab6db2e9e7ef6446" + integrity sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ== dependencies: - undici-types "~5.26.4" + undici-types "~7.12.0" "@types/seedrandom@3.0.1": version "3.0.1" @@ -769,9 +779,9 @@ base64-js@^1.3.1: integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== bignumber.js@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.0.tgz#bdba7e2a4c1a2eba08290e8dcad4f36393c92acd" - integrity sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA== + version "9.3.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== binary-extensions@^2.0.0: version "2.3.0" @@ -779,14 +789,14 @@ binary-extensions@^2.0.0: integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== boxen@^5.1.2: version "5.1.2" @@ -803,9 +813,9 @@ boxen@^5.1.2: wrap-ansi "^7.0.0" brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" @@ -988,9 +998,9 @@ cross-fetch@^4.0.0: node-fetch "^2.7.0" debug@4, debug@^4.1.1, debug@^4.3.5: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" @@ -1027,7 +1037,7 @@ dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -elliptic@6.6.1: +elliptic@6.6.1, elliptic@^6.5.4: version "6.6.1" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== @@ -1040,19 +1050,6 @@ elliptic@6.6.1: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - emittery@0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.0.tgz#bb373c660a9d421bb44706ec4967ed50c02a8026" @@ -1094,35 +1091,36 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: es-errors "^1.3.0" esbuild@~0.25.0: - version "0.25.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.5.tgz#71075054993fdfae76c66586f9b9c1f8d7edd430" - integrity sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ== + version "0.25.10" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.10.tgz#37f5aa5cd14500f141be121c01b096ca83ac34a9" + integrity sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ== optionalDependencies: - "@esbuild/aix-ppc64" "0.25.5" - "@esbuild/android-arm" "0.25.5" - "@esbuild/android-arm64" "0.25.5" - "@esbuild/android-x64" "0.25.5" - "@esbuild/darwin-arm64" "0.25.5" - "@esbuild/darwin-x64" "0.25.5" - "@esbuild/freebsd-arm64" "0.25.5" - "@esbuild/freebsd-x64" "0.25.5" - "@esbuild/linux-arm" "0.25.5" - "@esbuild/linux-arm64" "0.25.5" - "@esbuild/linux-ia32" "0.25.5" - "@esbuild/linux-loong64" "0.25.5" - "@esbuild/linux-mips64el" "0.25.5" - "@esbuild/linux-ppc64" "0.25.5" - "@esbuild/linux-riscv64" "0.25.5" - "@esbuild/linux-s390x" "0.25.5" - "@esbuild/linux-x64" "0.25.5" - "@esbuild/netbsd-arm64" "0.25.5" - "@esbuild/netbsd-x64" "0.25.5" - "@esbuild/openbsd-arm64" "0.25.5" - "@esbuild/openbsd-x64" "0.25.5" - "@esbuild/sunos-x64" "0.25.5" - "@esbuild/win32-arm64" "0.25.5" - "@esbuild/win32-ia32" "0.25.5" - "@esbuild/win32-x64" "0.25.5" + "@esbuild/aix-ppc64" "0.25.10" + "@esbuild/android-arm" "0.25.10" + "@esbuild/android-arm64" "0.25.10" + "@esbuild/android-x64" "0.25.10" + "@esbuild/darwin-arm64" "0.25.10" + "@esbuild/darwin-x64" "0.25.10" + "@esbuild/freebsd-arm64" "0.25.10" + "@esbuild/freebsd-x64" "0.25.10" + "@esbuild/linux-arm" "0.25.10" + "@esbuild/linux-arm64" "0.25.10" + "@esbuild/linux-ia32" "0.25.10" + "@esbuild/linux-loong64" "0.25.10" + "@esbuild/linux-mips64el" "0.25.10" + "@esbuild/linux-ppc64" "0.25.10" + "@esbuild/linux-riscv64" "0.25.10" + "@esbuild/linux-s390x" "0.25.10" + "@esbuild/linux-x64" "0.25.10" + "@esbuild/netbsd-arm64" "0.25.10" + "@esbuild/netbsd-x64" "0.25.10" + "@esbuild/openbsd-arm64" "0.25.10" + "@esbuild/openbsd-x64" "0.25.10" + "@esbuild/openharmony-arm64" "0.25.10" + "@esbuild/sunos-x64" "0.25.10" + "@esbuild/win32-arm64" "0.25.10" + "@esbuild/win32-ia32" "0.25.10" + "@esbuild/win32-x64" "0.25.10" escalade@^3.1.1: version "3.2.0" @@ -1159,10 +1157,10 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -fdir@^6.4.3: - version "6.4.3" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" - integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== fill-range@^7.1.1: version "7.1.1" @@ -1185,9 +1183,9 @@ flat@^5.0.2: integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== follow-redirects@^1.12.1: - version "1.15.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== for-each@^0.3.5: version "0.3.5" @@ -1295,17 +1293,15 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6: integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== hardhat@^2.24.1: - version "2.24.1" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.24.1.tgz#08cc2c43210be21eb1e7900123b63f465f656eb7" - integrity sha512-3iwrO2liEGCw1rz/l/mlB1rSNexCc4CFcMj0DlvjXGChzmD3sGUgLwWDOZPf+ya8MEm5ZhO1oprRVmb/wVi0YA== + version "2.26.3" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.26.3.tgz#87f3f4b6d1001970299d5bff135d57e8adae7a07" + integrity sha512-gBfjbxCCEaRgMCRgTpjo1CEoJwqNPhyGMMVHYZJxoQ3LLftp2erSVf8ZF6hTQC0r2wst4NcqNmLWqMnHg1quTw== dependencies: "@ethereumjs/util" "^9.1.0" "@ethersproject/abi" "^5.1.2" - "@nomicfoundation/edr" "^0.11.0" + "@nomicfoundation/edr" "^0.11.3" "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" adm-zip "^0.4.16" aggregate-error "^3.0.0" ansi-escapes "^4.3.0" @@ -1754,9 +1750,9 @@ node-gyp-build@4.4.0: integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ== node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" - integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -1821,10 +1817,10 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" - integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== possible-typed-array-names@^1.0.0: version "1.1.0" @@ -2039,12 +2035,12 @@ supports-color@^8.1.1: has-flag "^4.0.0" tinyglobby@^0.2.6: - version "0.2.12" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.12.tgz#ac941a42e0c5773bd0b5d08f32de82e74a1a61b5" - integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww== + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: - fdir "^6.4.3" - picomatch "^4.0.2" + fdir "^6.5.0" + picomatch "^4.0.3" tmp@0.0.33: version "0.0.33" @@ -2081,9 +2077,9 @@ tsort@0.0.1: integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== tsx@^4.19.4: - version "4.19.4" - resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.4.tgz#647b4141f4fdd9d773a9b564876773d2846901f4" - integrity sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q== + version "4.20.5" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.20.5.tgz#856c8b2f114c50a9f4ae108126967a167f240dc7" + integrity sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw== dependencies: esbuild "~0.25.0" get-tsconfig "^4.7.5" @@ -2105,15 +2101,15 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~7.12.0: + version "7.12.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.12.0.tgz#15c5c7475c2a3ba30659529f5cdb4674b622fafb" + integrity sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ== undici@^5.14.0: - version "5.28.5" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.5.tgz#b2b94b6bf8f1d919bc5a6f31f2c01deb02e54d4b" - integrity sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA== + version "5.29.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.29.0.tgz#419595449ae3f2cdcba3580a2e8903399bd1f5a3" + integrity sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg== dependencies: "@fastify/busboy" "^2.0.0" @@ -2452,9 +2448,9 @@ ws@^7.4.6: integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.17.1: - version "8.18.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" - integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== y18n@^5.0.5: version "5.0.8" @@ -2495,6 +2491,6 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod@^3.21.4: - version "3.25.48" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.48.tgz#6c2b536fbb519905e8f4a4ac58743de4d5331bb2" - integrity sha512-0X1mz8FtgEIvaxGjdIImYpZEaZMrund9pGXm3M6vM7Reba0e2eI71KPjSCGXBfwKDPwPoywf6waUKc3/tFvX2Q== + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==